<commit_before>//! Traits for working with JavaScript objects.
//!
//! This module defines the [`Object`](Object) trait, which is implemented
//! by all object types in the [JavaScript type hierarchy][hierarchy]. This
//! trait provides key operations in the semantics of JavaScript objects,
//! such as getting and setting an object's properties.
//!
//! ## Property Keys
//!
//! Object properties are accessed by a _property key_, which in JavaScript
//! can be a string or [symbol][symbol]. (Neon does not yet have support for
//! symbols.) For convenience, the [`PropertyKey`](PropertyKey) trait allows
//! Neon programs to use various Rust string types, as well as numeric types,
//! as keys when accessing object properties, converting the keys to strings
//! as necessary:
//!
//! ```
//! # use neon::prelude::*;
//! fn set_and_check<'a>(
//!     cx: &mut impl Context<'a>,
//!     obj: Handle<'a, JsObject>
//! ) -> JsResult<'a, JsValue> {
//!     let value = cx.string("hello!");
//!     // set property "17" with integer shorthand
//!     obj.set(cx, 17, value)?;
//!     // get property "17" with string shorthand
//!     // returns the same value ("hello!")
//!     obj.get(cx, "17")
//! }
//! ```
//!
//! [hierarchy]: crate::types#the-javascript-type-hierarchy
//! [symbol]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol

use crate::{
    context::{internal::Env, Context},
    handle::{Handle, Managed, Root},
    result::{NeonResult, Throw},
    sys::{self, raw, Status},
    types::{build, function::CallOptions, utf8::Utf8, JsFunction, JsUndefined, JsValue, Value},
};

#[cfg(feature = "napi-6")]
use crate::{result::JsResult, types::JsArray};

/// A property key in a JavaScript object.
pub trait PropertyKey {
    unsafe fn get_from<'c, C: Context<'c>>(
        self,
        cx: &mut C,
        out: &mut raw::Local,
        obj: raw::Local,
    ) -> bool;

    unsafe fn set_from<'c, C: Context<'c>>(
        self,
        cx: &mut C,
        out: &mut bool,
        obj: raw::Local,
        val: raw::Local,
    ) -> bool;
}

impl PropertyKey for u32 {
    unsafe fn get_from<'c, C: Context<'c>>(
        self,
        cx: &mut C,
        out: &mut raw::Local,
        obj: raw::Local,
    ) -> bool {
        sys::object::get_index(out, cx.env().to_raw(), obj, self)
    }

    unsafe fn set_from<'c, C: Context<'c>>(
        self,
        cx: &mut C,
        out: &mut bool,
        obj: raw::Local,
        val: raw::Local,
    ) -> bool {
        sys::object::set_index(out, cx.env().to_raw(), obj, self, val)
    }
}

impl<'a, K: Value> PropertyKey for Handle<'a, K> {
    unsafe fn get_from<'c, C: Context<'c>>(
        self,
        cx: &mut C,
        out: &mut raw::Local,
        obj: raw::Local,
    ) -> bool {
        let env = cx.env().to_raw();

        sys::object::get(out, env, obj, self.to_raw())
    }

    unsafe fn set_from<'c, C: Context<'c>>(
        self,
        cx: &mut C,
        out: &mut bool,
        obj: raw::Local,
        val: raw::Local,
    ) -> bool {
        let env = cx.env().to_raw();

        sys::object::set(out, env, obj, self.to_raw(), val)
    }
}

impl<'a> PropertyKey for &'a str {
    unsafe fn get_from<'c, C: Context<'c>>(
        self,
        cx: &mut C,
        out: &mut raw::Local,
        obj: raw::Local,
    ) -> bool {
        let (ptr, len) = Utf8::from(self).into_small_unwrap().lower();
        let env = cx.env().to_raw();

        sys::object::get_string(env, out, obj, ptr, len)
    }

    unsafe fn set_from<'c, C: Context<'c>>(
        self,
        cx: &mut C,
        out: &mut bool,
        obj: raw::Local,
        val: raw::Local,
    ) -> bool {
        let (ptr, len) = Utf8::from(self).into_small_unwrap().lower();
        let env = cx.env().to_raw();

        sys::object::set_string(env, out, obj, ptr, len, val)
    }
}

/// The trait of all object types.
pub trait Object: Value {
    /// Gets a property from a JavaScript object that may be `undefined` and
    /// attempts to downcast the value if it existed.
    fn get_opt<'a, V: Value, C: Context<'a>, K: PropertyKey>(
        &self,
        cx: &mut C,
        key: K,
    ) -> NeonResult<Option<Handle<'a, V>>> {
        let v = self.get_value(cx, key)?;

        if v.is_a::<JsUndefined, _>(cx) {
            return Ok(None);
        }

        v.downcast_or_throw(cx).map(Some)
    }

    /// Gets a property from a JavaScript object as a [`JsValue`].
    ///
    /// If a [`getter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get)
    /// is defined on the object, it will be called.
    fn get_value<'a, C: Context<'a>, K: PropertyKey>(
        &self,
        cx: &mut C,
        key: K,
    ) -> NeonResult<Handle<'a, JsValue>> {
        build(cx.env(), |out| unsafe {
            key.get_from(cx, out, self.to_raw())
        })
    }

    /// Gets a property from a JavaScript object and attempts to downcast as a specific type.
    /// Equivalent to calling `obj.get_value(&mut cx)?.downcast_or_throw(&mut cx)`.
    ///
    /// Throws an exception if the value is a different type.
    fn get<'a, V: Value, C: Context<'a>, K: PropertyKey>(
        &self,
        cx: &mut C,
        key: K,
    ) -> NeonResult<Handle<'a, V>> {
        self.get_value(cx, key)?.downcast_or_throw(cx)
    }

    #[cfg(feature = "napi-6")]
    #[cfg_attr(docsrs, doc(cfg(feature = "napi-6")))]
    fn get_own_property_names<'a, C: Context<'a>>(&self, cx: &mut C) -> JsResult<'a, JsArray> {
        let env = cx.env();

        build(cx.env(), |out| unsafe {
            sys::object::get_own_property_names(out, env.to_raw(), self.to_raw())
        })
    }

    #[cfg(feature = "napi-8")]
    fn freeze<'a, C: Context<'a>>(&self, cx: &mut C) -> NeonResult<&Self> {
        let env = cx.env().to_raw();
        let obj = self.to_raw();
        unsafe {
            match sys::object::freeze(env, obj) {
                Status::Ok => Ok(self),
                Status::PendingException => Err(Throw::new()),
                _ => cx.throw_type_error("object cannot be frozen"),
            }
        }
    }

    #[cfg(feature = "napi-8")]
    fn seal<'a, C: Context<'a>>(&self, cx: &mut C) -> NeonResult<&Self> {
        let env = cx.env().to_raw();
        let obj = self.to_raw();
        unsafe {
            match sys::object::seal(env, obj) {
                Status::Ok => Ok(self),
                Status::PendingException => Err(Throw::new()),
                _ => cx.throw_type_error("object cannot be sealed"),
            }
        }
    }

    fn set<'a, C: Context<'a>, K: PropertyKey, W: Value>(
        &self,
        cx: &mut C,
        key: K,
        val: Handle<W>,
    ) -> NeonResult<bool> {
        let mut result = false;
        if unsafe { key.set_from(cx, &mut result, self.to_raw(), val.to_raw()) } {
            Ok(result)
        } else {
            Err(Throw::new())
        }
    }

    fn root<'a, C: Context<'a>>(&self, cx: &mut C) -> Root<Self> {
        Root::new(cx, self)
    }

    fn call_method_with<'a, C, K>(&self, cx: &mut C, method: K) -> NeonResult<CallOptions<'a>>
    where
        C: Context<'a>,
        K: PropertyKey,
    {
        let mut options = self.get::<JsFunction, _, _>(cx, method)?.call_with(cx);
        options.this(JsValue::new_internal(self.to_raw()));
        Ok(options)
    }
}

/// The trait of types that can be a function's `this` binding.
pub unsafe trait This: Managed {
    #[allow(clippy::wrong_self_convention)]
    fn as_this(env: Env, h: raw::Local) -> Self;
}
<commit_msg>Fix unused warning on Node-API < 8<commit_after>//! Traits for working with JavaScript objects.
//!
//! This module defines the [`Object`](Object) trait, which is implemented
//! by all object types in the [JavaScript type hierarchy][hierarchy]. This
//! trait provides key operations in the semantics of JavaScript objects,
//! such as getting and setting an object's properties.
//!
//! ## Property Keys
//!
//! Object properties are accessed by a _property key_, which in JavaScript
//! can be a string or [symbol][symbol]. (Neon does not yet have support for
//! symbols.) For convenience, the [`PropertyKey`](PropertyKey) trait allows
//! Neon programs to use various Rust string types, as well as numeric types,
//! as keys when accessing object properties, converting the keys to strings
//! as necessary:
//!
//! ```
//! # use neon::prelude::*;
//! fn set_and_check<'a>(
//!     cx: &mut impl Context<'a>,
//!     obj: Handle<'a, JsObject>
//! ) -> JsResult<'a, JsValue> {
//!     let value = cx.string("hello!");
//!     // set property "17" with integer shorthand
//!     obj.set(cx, 17, value)?;
//!     // get property "17" with string shorthand
//!     // returns the same value ("hello!")
//!     obj.get(cx, "17")
//! }
//! ```
//!
//! [hierarchy]: crate::types#the-javascript-type-hierarchy
//! [symbol]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol

use crate::{
    context::{internal::Env, Context},
    handle::{Handle, Managed, Root},
    result::{NeonResult, Throw},
    sys::{self, raw},
    types::{build, function::CallOptions, utf8::Utf8, JsFunction, JsUndefined, JsValue, Value},
};

#[cfg(feature = "napi-6")]
use crate::{result::JsResult, types::JsArray};

/// A property key in a JavaScript object.
pub trait PropertyKey {
    unsafe fn get_from<'c, C: Context<'c>>(
        self,
        cx: &mut C,
        out: &mut raw::Local,
        obj: raw::Local,
    ) -> bool;

    unsafe fn set_from<'c, C: Context<'c>>(
        self,
        cx: &mut C,
        out: &mut bool,
        obj: raw::Local,
        val: raw::Local,
    ) -> bool;
}

impl PropertyKey for u32 {
    unsafe fn get_from<'c, C: Context<'c>>(
        self,
        cx: &mut C,
        out: &mut raw::Local,
        obj: raw::Local,
    ) -> bool {
        sys::object::get_index(out, cx.env().to_raw(), obj, self)
    }

    unsafe fn set_from<'c, C: Context<'c>>(
        self,
        cx: &mut C,
        out: &mut bool,
        obj: raw::Local,
        val: raw::Local,
    ) -> bool {
        sys::object::set_index(out, cx.env().to_raw(), obj, self, val)
    }
}

impl<'a, K: Value> PropertyKey for Handle<'a, K> {
    unsafe fn get_from<'c, C: Context<'c>>(
        self,
        cx: &mut C,
        out: &mut raw::Local,
        obj: raw::Local,
    ) -> bool {
        let env = cx.env().to_raw();

        sys::object::get(out, env, obj, self.to_raw())
    }

    unsafe fn set_from<'c, C: Context<'c>>(
        self,
        cx: &mut C,
        out: &mut bool,
        obj: raw::Local,
        val: raw::Local,
    ) -> bool {
        let env = cx.env().to_raw();

        sys::object::set(out, env, obj, self.to_raw(), val)
    }
}

impl<'a> PropertyKey for &'a str {
    unsafe fn get_from<'c, C: Context<'c>>(
        self,
        cx: &mut C,
        out: &mut raw::Local,
        obj: raw::Local,
    ) -> bool {
        let (ptr, len) = Utf8::from(self).into_small_unwrap().lower();
        let env = cx.env().to_raw();

        sys::object::get_string(env, out, obj, ptr, len)
    }

    unsafe fn set_from<'c, C: Context<'c>>(
        self,
        cx: &mut C,
        out: &mut bool,
        obj: raw::Local,
        val: raw::Local,
    ) -> bool {
        let (ptr, len) = Utf8::from(self).into_small_unwrap().lower();
        let env = cx.env().to_raw();

        sys::object::set_string(env, out, obj, ptr, len, val)
    }
}

/// The trait of all object types.
pub trait Object: Value {
    /// Gets a property from a JavaScript object that may be `undefined` and
    /// attempts to downcast the value if it existed.
    fn get_opt<'a, V: Value, C: Context<'a>, K: PropertyKey>(
        &self,
        cx: &mut C,
        key: K,
    ) -> NeonResult<Option<Handle<'a, V>>> {
        let v = self.get_value(cx, key)?;

        if v.is_a::<JsUndefined, _>(cx) {
            return Ok(None);
        }

        v.downcast_or_throw(cx).map(Some)
    }

    /// Gets a property from a JavaScript object as a [`JsValue`].
    ///
    /// If a [`getter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get)
    /// is defined on the object, it will be called.
    fn get_value<'a, C: Context<'a>, K: PropertyKey>(
        &self,
        cx: &mut C,
        key: K,
    ) -> NeonResult<Handle<'a, JsValue>> {
        build(cx.env(), |out| unsafe {
            key.get_from(cx, out, self.to_raw())
        })
    }

    /// Gets a property from a JavaScript object and attempts to downcast as a specific type.
    /// Equivalent to calling `obj.get_value(&mut cx)?.downcast_or_throw(&mut cx)`.
    ///
    /// Throws an exception if the value is a different type.
    fn get<'a, V: Value, C: Context<'a>, K: PropertyKey>(
        &self,
        cx: &mut C,
        key: K,
    ) -> NeonResult<Handle<'a, V>> {
        self.get_value(cx, key)?.downcast_or_throw(cx)
    }

    #[cfg(feature = "napi-6")]
    #[cfg_attr(docsrs, doc(cfg(feature = "napi-6")))]
    fn get_own_property_names<'a, C: Context<'a>>(&self, cx: &mut C) -> JsResult<'a, JsArray> {
        let env = cx.env();

        build(cx.env(), |out| unsafe {
            sys::object::get_own_property_names(out, env.to_raw(), self.to_raw())
        })
    }

    #[cfg(feature = "napi-8")]
    fn freeze<'a, C: Context<'a>>(&self, cx: &mut C) -> NeonResult<&Self> {
        let env = cx.env().to_raw();
        let obj = self.to_raw();
        unsafe {
            match sys::object::freeze(env, obj) {
                sys::Status::Ok => Ok(self),
                sys::Status::PendingException => Err(Throw::new()),
                _ => cx.throw_type_error("object cannot be frozen"),
            }
        }
    }

    #[cfg(feature = "napi-8")]
    fn seal<'a, C: Context<'a>>(&self, cx: &mut C) -> NeonResult<&Self> {
        let env = cx.env().to_raw();
        let obj = self.to_raw();
        unsafe {
            match sys::object::seal(env, obj) {
                sys::Status::Ok => Ok(self),
                sys::Status::PendingException => Err(Throw::new()),
                _ => cx.throw_type_error("object cannot be sealed"),
            }
        }
    }

    fn set<'a, C: Context<'a>, K: PropertyKey, W: Value>(
        &self,
        cx: &mut C,
        key: K,
        val: Handle<W>,
    ) -> NeonResult<bool> {
        let mut result = false;
        if unsafe { key.set_from(cx, &mut result, self.to_raw(), val.to_raw()) } {
            Ok(result)
        } else {
            Err(Throw::new())
        }
    }

    fn root<'a, C: Context<'a>>(&self, cx: &mut C) -> Root<Self> {
        Root::new(cx, self)
    }

    fn call_method_with<'a, C, K>(&self, cx: &mut C, method: K) -> NeonResult<CallOptions<'a>>
    where
        C: Context<'a>,
        K: PropertyKey,
    {
        let mut options = self.get::<JsFunction, _, _>(cx, method)?.call_with(cx);
        options.this(JsValue::new_internal(self.to_raw()));
        Ok(options)
    }
}

/// The trait of types that can be a function's `this` binding.
pub unsafe trait This: Managed {
    #[allow(clippy::wrong_self_convention)]
    fn as_this(env: Env, h: raw::Local) -> Self;
}
<|endoftext|>


<commit_before>use crate::{
    analysis::{
        imports::Imports,
        properties::{get_property_ref_modes, Property},
        rust_type::*,
    },
    config::{self, GObject},
    env::Env,
    library,
    traits::*,
};

pub fn analyze(
    env: &Env,
    props: &[library::Property],
    type_tid: library::TypeId,
    obj: &GObject,
    imports: &mut Imports,
) -> Vec<Property> {
    let generate_builders = env
        .config
        .objects
        .contains_key(&format!("{}Builder", obj.name));
    if !generate_builders {
        return Vec::new();
    }

    let mut builder_properties = analyze_class(env, props, obj, imports);

    for &super_tid in env.class_hierarchy.supertypes(type_tid) {
        let type_ = env.type_(super_tid);

        let super_class: &library::Class = match type_.maybe_ref() {
            Some(super_class) => super_class,
            None => continue,
        };

        let new_builder_properties = analyze_class(env, &super_class.properties, obj, imports);
        builder_properties.extend(new_builder_properties);
    }

    builder_properties
}

pub fn analyze_class(
    env: &Env,
    props: &[library::Property],
    obj: &GObject,
    imports: &mut Imports,
) -> Vec<Property> {
    let mut builder_properties = Vec::new();

    for prop in props {
        let configured_properties = obj.properties.matched(&prop.name);
        if configured_properties.iter().any(|f| f.ignore) {
            continue;
        }

        if env.is_totally_deprecated(prop.deprecated_version) {
            continue;
        }
        let builder = analyze_property(env, prop, &configured_properties, imports);
        if let Some(builder) = builder {
            builder_properties.push(builder);
        }
    }

    builder_properties
}

fn analyze_property(
    env: &Env,
    prop: &library::Property,
    configured_properties: &[&config::properties::Property],
    imports: &mut Imports,
) -> Option<Property> {
    let name = prop.name.clone();

    let prop_version = configured_properties
        .iter()
        .filter_map(|f| f.version)
        .min()
        .or(prop.version)
        .or_else(|| Some(env.config.min_cfg_version));

    let for_builder = prop.construct_only || prop.construct || prop.writable;
    if !for_builder {
        return None;
    }
    if let Ok(ref s) = used_rust_type(env, prop.typ, false) {
        imports.add_used_type(s, prop.version);
    }

    let (get_out_ref_mode, set_in_ref_mode, nullable) = get_property_ref_modes(env, prop);

    Some(Property {
        name: name.clone(),
        var_name: String::new(),
        typ: prop.typ,
        is_get: false,
        func_name: String::new(),
        nullable,
        get_out_ref_mode,
        set_in_ref_mode,
        version: prop_version,
        deprecated_version: prop.deprecated_version,
    })
}
<commit_msg>Don't generate unused "use glib::GString" for builder<commit_after>use crate::{
    analysis::{
        imports::Imports,
        properties::{get_property_ref_modes, Property},
        rust_type::*,
    },
    config::{self, GObject},
    env::Env,
    library,
    traits::*,
};

pub fn analyze(
    env: &Env,
    props: &[library::Property],
    type_tid: library::TypeId,
    obj: &GObject,
    imports: &mut Imports,
) -> Vec<Property> {
    let generate_builders = env
        .config
        .objects
        .contains_key(&format!("{}Builder", obj.name));
    if !generate_builders {
        return Vec::new();
    }

    let mut builder_properties = analyze_class(env, props, obj, imports);

    for &super_tid in env.class_hierarchy.supertypes(type_tid) {
        let type_ = env.type_(super_tid);

        let super_class: &library::Class = match type_.maybe_ref() {
            Some(super_class) => super_class,
            None => continue,
        };

        let new_builder_properties = analyze_class(env, &super_class.properties, obj, imports);
        builder_properties.extend(new_builder_properties);
    }

    builder_properties
}

pub fn analyze_class(
    env: &Env,
    props: &[library::Property],
    obj: &GObject,
    imports: &mut Imports,
) -> Vec<Property> {
    let mut builder_properties = Vec::new();

    for prop in props {
        let configured_properties = obj.properties.matched(&prop.name);
        if configured_properties.iter().any(|f| f.ignore) {
            continue;
        }

        if env.is_totally_deprecated(prop.deprecated_version) {
            continue;
        }
        let builder = analyze_property(env, prop, &configured_properties, imports);
        if let Some(builder) = builder {
            builder_properties.push(builder);
        }
    }

    builder_properties
}

fn analyze_property(
    env: &Env,
    prop: &library::Property,
    configured_properties: &[&config::properties::Property],
    imports: &mut Imports,
) -> Option<Property> {
    let name = prop.name.clone();

    let prop_version = configured_properties
        .iter()
        .filter_map(|f| f.version)
        .min()
        .or(prop.version)
        .or_else(|| Some(env.config.min_cfg_version));

    let for_builder = prop.construct_only || prop.construct || prop.writable;
    if !for_builder {
        return None;
    }
    if let Ok(ref s) = used_rust_type(env, prop.typ, false) {
        if !s.contains("GString") {
            imports.add_used_type(s, prop.version);
        }
    }

    let (get_out_ref_mode, set_in_ref_mode, nullable) = get_property_ref_modes(env, prop);

    Some(Property {
        name: name.clone(),
        var_name: String::new(),
        typ: prop.typ,
        is_get: false,
        func_name: String::new(),
        nullable,
        get_out_ref_mode,
        set_in_ref_mode,
        version: prop_version,
        deprecated_version: prop.deprecated_version,
    })
}
<|endoftext|>


<commit_before>
use assembler::data_range::DataRange;

enum Record<'a> {
  /// A data record. Supported in i8, i16 and i32.
  Data { address: u16, value: &'a [u8] },
  /// An end-of-file record. Supported in i8, i16 and i32.
  EndOfFile
}

mod type_codes {
  /// Type code for a Data record.
  pub const DATA_TYPE_CODE: u8 = 0x00;
  /// Type code for an End-of-File record.
  pub const END_OF_FILE_TYPE_CODE: u8 = 0x01;
}

impl<'a> Record<'a> {
  /**
   @return String value of the Intel HEX record for the receiver, excluding a trailing newline.
   */
  pub fn as_formatted_string(&self) -> String {
    match self {
      &Record::Data {address, value} => format_record(address, value, type_codes::DATA_TYPE_CODE),
      &Record::EndOfFile             => format_record(0x0000 , &[],   type_codes::END_OF_FILE_TYPE_CODE)
    }
  }
}

/**
 An Intel HEX record is composed of the following elements:
 +----------------+-----------------+---------------+-----------+---------+---------------+
 | Start Code (:) | Byte Count (u8) | Address (u16) | Type (u8) | Data... | Checksum (u8) |
 +----------------+-----------------+---------------+-----------+---------+---------------+
 */
fn format_record<'a>(address: u16, data: &'a [u8], type_code: u8) -> String {
  assert!(data.len() <= 255);

  // Construct the checksum region.
  let length_of_checksum_region = 4 + data.len();
  let mut checksum_region = Vec::<u8>::with_capacity(length_of_checksum_region);
  checksum_region.push(data.len() as u8);
  checksum_region.push(((address & 0xFF00) >> 8) as u8);
  checksum_region.push(((address & 0x00FF) >> 0) as u8);
  checksum_region.push(type_code);
  checksum_region.extend_from_slice(data);
  let checksum = ihex_checksum(checksum_region.as_slice());

  // Construct the record, excluding the start code and checksum.
  let checksum_region_string =
    checksum_region
      .iter()
      .map(|byte: &u8| format!("{:02X}", byte))
      .fold(String::new(), |acc, value| acc + &value);

  // Construct the formatted version of the record.
  format!(":{}{:02X}", checksum_region_string, checksum)
}

/**
 The Intel HEX checksum is computed as the two's complement of the sum of all
 elements preceding, excluding the Start Code. This is the Byte Count, Address,
 Record Type and Data.
 @param data Slice view of the checksum region.
 @return The Intel HEX checksum of the supplied region.
 */
fn ihex_checksum<'a>(data: &'a [u8]) -> u8 {
  let sum: usize = data.iter().fold(0, |acc, &value| acc.wrapping_add(value as usize));
  (((sum & 0xFF) as u8) ^ 0xFF).wrapping_add(1)
}

// MARK: - Tests

#[cfg(test)]
mod tests {

  use super::Record;
  use super::{format_record, ihex_checksum};
  use super::type_codes;

  #[test]
  fn test_ihex_checksum() {
    assert_eq!(ihex_checksum(&vec![]), 0x00);
    assert_eq!(ihex_checksum(&vec![0x10,0x01,0x00,0x00,0x21,0x46,0x01,0x36,0x01,0x21,0x47,0x01,0x36,0x00,0x7E,0xFE,0x09,0xD2,0x19,0x01]), 0x40);
    assert_eq!(ihex_checksum(&vec![0x10,0x01,0x10,0x00,0x21,0x46,0x01,0x7E,0x17,0xC2,0x00,0x01,0xFF,0x5F,0x16,0x00,0x21,0x48,0x01,0x19]), 0x28);
    assert_eq!(ihex_checksum(&vec![0x10,0x01,0x20,0x00,0x19,0x4E,0x79,0x23,0x46,0x23,0x96,0x57,0x78,0x23,0x9E,0xDA,0x3F,0x01,0xB2,0xCA]), 0xA7);
    assert_eq!(ihex_checksum(&vec![0x10,0x01,0x30,0x00,0x3F,0x01,0x56,0x70,0x2B,0x5E,0x71,0x2B,0x72,0x2B,0x73,0x21,0x46,0x01,0x34,0x21]), 0xC7);
    assert_eq!(ihex_checksum(&vec![0x00,0x00,0x00,0x01]), 0xFF);
  }

  #[test]
  fn test_format_record() {
    assert_eq!(format_record(0x0100, &vec![0x21,0x46,0x01,0x36,0x01,0x21,0x47,0x01,0x36,0x00,0x7E,0xFE,0x09,0xD2,0x19,0x01], type_codes::DATA_TYPE_CODE), String::from(":10010000214601360121470136007EFE09D2190140"));
    assert_eq!(format_record(0x0110, &vec![0x21,0x46,0x01,0x7E,0x17,0xC2,0x00,0x01,0xFF,0x5F,0x16,0x00,0x21,0x48,0x01,0x19], type_codes::DATA_TYPE_CODE), String::from(":100110002146017E17C20001FF5F16002148011928"));
    assert_eq!(format_record(0x0120, &vec![0x19,0x4E,0x79,0x23,0x46,0x23,0x96,0x57,0x78,0x23,0x9E,0xDA,0x3F,0x01,0xB2,0xCA], type_codes::DATA_TYPE_CODE), String::from(":10012000194E79234623965778239EDA3F01B2CAA7"));
    assert_eq!(format_record(0x0130, &vec![0x3F,0x01,0x56,0x70,0x2B,0x5E,0x71,0x2B,0x72,0x2B,0x73,0x21,0x46,0x01,0x34,0x21], type_codes::DATA_TYPE_CODE), String::from(":100130003F0156702B5E712B722B732146013421C7"));
    assert_eq!(format_record(0x0000, &[], type_codes::END_OF_FILE_TYPE_CODE), String::from(":00000001FF"));
  }

  #[test]
  fn test_record_as_formatted_string() {
    let eof_record = Record::EndOfFile;
    assert_eq!(eof_record.as_formatted_string(), String::from(":00000001FF"));

    let data_record = Record::Data { address: 0x0100, value: &vec![0x21,0x46,0x01,0x36,0x01,0x21,0x47,0x01,0x36,0x00,0x7E,0xFE,0x09,0xD2,0x19,0x01] };
    assert_eq!(data_record.as_formatted_string(), String::from(":10010000214601360121470136007EFE09D2190140"));
  }

}
<commit_msg>Add tests for more i8hex edge cases.<commit_after>
use assembler::data_range;
use assembler::data_range::DataRange;

// MARK: - Intel HEX Formatting Utilities

enum Record<'a> {
  /// A data record. Supported in i8, i16 and i32.
  Data { address: u16, value: &'a [u8] },
  /// An end-of-file record. Supported in i8, i16 and i32.
  EndOfFile
}

mod type_codes {
  /// Type code for a Data record.
  pub const DATA_TYPE_CODE: u8 = 0x00;
  /// Type code for an End-of-File record.
  pub const END_OF_FILE_TYPE_CODE: u8 = 0x01;
}

impl<'a> Record<'a> {
  /**
   @return String value of the Intel HEX record for the receiver, excluding a trailing newline.
   */
  pub fn as_formatted_string(&self) -> String {
    match self {
      &Record::Data {address, value} => format_record(address, value, type_codes::DATA_TYPE_CODE),
      &Record::EndOfFile             => format_record(0x0000 , &[],   type_codes::END_OF_FILE_TYPE_CODE)
    }
  }
}

/**
 An Intel HEX record is composed of the following elements:
 +----------------+-----------------+---------------+-----------+---------+---------------+
 | Start Code (:) | Byte Count (u8) | Address (u16) | Type (u8) | Data... | Checksum (u8) |
 +----------------+-----------------+---------------+-----------+---------+---------------+
 */
fn format_record<'a>(address: u16, data: &'a [u8], type_code: u8) -> String {
  assert!(data.len() <= 255);

  // Construct the checksum region.
  let length_of_checksum_region = 4 + data.len();
  let mut checksum_region = Vec::<u8>::with_capacity(length_of_checksum_region);
  checksum_region.push(data.len() as u8);
  checksum_region.push(((address & 0xFF00) >> 8) as u8);
  checksum_region.push(((address & 0x00FF) >> 0) as u8);
  checksum_region.push(type_code);
  checksum_region.extend_from_slice(data);
  let checksum = ihex_checksum(checksum_region.as_slice());

  // Construct the record, excluding the start code and checksum.
  let checksum_region_string =
    checksum_region
      .iter()
      .map(|byte: &u8| format!("{:02X}", byte))
      .fold(String::new(), |acc, value| acc + &value);

  // Construct the formatted version of the record.
  format!(":{}{:02X}", checksum_region_string, checksum)
}

/**
 The Intel HEX checksum is computed as the two's complement of the sum of all
 elements preceding, excluding the Start Code. This is the Byte Count, Address,
 Record Type and Data.
 @param data Slice view of the checksum region.
 @return The Intel HEX checksum of the supplied region.
 */
fn ihex_checksum<'a>(data: &'a [u8]) -> u8 {
  let sum: usize = data.iter().fold(0, |acc, &value| acc.wrapping_add(value as usize));
  (((sum & 0xFF) as u8) ^ 0xFF).wrapping_add(1)
}

// MARK: - Public API

/**
 Converts the provided data ranges into a single Intel HEX record. These data ranges
 cannot overlap and still yield a valid I8HEX record. It is the responsibility of
 the caller to ensure this does not happen.
 @param ranges The data ranges to convert to I8HEX format.
 @return The complete I8HEX record (including EOF) of the given data ranges.
 */
pub fn i8hex_representation_of_data_ranges<'a>(ranges: &'a [&'a DataRange]) -> String {
  assert!(data_range::find_overlapping_data_ranges(ranges).len() == 0);

  // All records are collected into a list.
  let mut records = Vec::<Record>::new();

  for range in ranges {

    // The range will be sub-divded into chunks of up to 16 bytes, so sub-address must be tracked.
    let mut address_for_record = range.address_range().start.as_u16();

    // Iterate over the data range in groups of up to 16.
    for data_for_record in range.data().as_slice().chunks(16) {

      // Create a new data record for the chunk.
      records.push( Record::Data { address: address_for_record, value: data_for_record } );

      // Increment the address by the number of bytes emitted in the record.
      address_for_record += data_for_record.len() as u16;
    }
  }

  // All I8HEX files end in an EOF marker.
  records.push(Record::EndOfFile);

  // Obtain the formatted representation of each record and join with newlines for display.
  records
    .iter()
    .map(|record| record.as_formatted_string())
    .collect::<Vec<_>>()
    .join("\n")
}

// MARK: - Tests

#[cfg(test)]
mod tests {

  use super::Record;
  use super::{format_record, i8hex_representation_of_data_ranges, ihex_checksum};
  use super::type_codes;

  use assembler::data_range::DataRange;
  use assembler::u12::*;

  #[test]
  fn test_ihex_checksum() {
    assert_eq!(ihex_checksum(&vec![]), 0x00);
    assert_eq!(ihex_checksum(&vec![0x10,0x01,0x00,0x00,0x21,0x46,0x01,0x36,0x01,0x21,0x47,0x01,0x36,0x00,0x7E,0xFE,0x09,0xD2,0x19,0x01]), 0x40);
    assert_eq!(ihex_checksum(&vec![0x10,0x01,0x10,0x00,0x21,0x46,0x01,0x7E,0x17,0xC2,0x00,0x01,0xFF,0x5F,0x16,0x00,0x21,0x48,0x01,0x19]), 0x28);
    assert_eq!(ihex_checksum(&vec![0x10,0x01,0x20,0x00,0x19,0x4E,0x79,0x23,0x46,0x23,0x96,0x57,0x78,0x23,0x9E,0xDA,0x3F,0x01,0xB2,0xCA]), 0xA7);
    assert_eq!(ihex_checksum(&vec![0x10,0x01,0x30,0x00,0x3F,0x01,0x56,0x70,0x2B,0x5E,0x71,0x2B,0x72,0x2B,0x73,0x21,0x46,0x01,0x34,0x21]), 0xC7);
    assert_eq!(ihex_checksum(&vec![0x00,0x00,0x00,0x01]), 0xFF);
  }

  #[test]
  fn test_format_record() {
    assert_eq!(format_record(0x0100, &vec![0x21,0x46,0x01,0x36,0x01,0x21,0x47,0x01,0x36,0x00,0x7E,0xFE,0x09,0xD2,0x19,0x01], type_codes::DATA_TYPE_CODE), String::from(":10010000214601360121470136007EFE09D2190140"));
    assert_eq!(format_record(0x0110, &vec![0x21,0x46,0x01,0x7E,0x17,0xC2,0x00,0x01,0xFF,0x5F,0x16,0x00,0x21,0x48,0x01,0x19], type_codes::DATA_TYPE_CODE), String::from(":100110002146017E17C20001FF5F16002148011928"));
    assert_eq!(format_record(0x0120, &vec![0x19,0x4E,0x79,0x23,0x46,0x23,0x96,0x57,0x78,0x23,0x9E,0xDA,0x3F,0x01,0xB2,0xCA], type_codes::DATA_TYPE_CODE), String::from(":10012000194E79234623965778239EDA3F01B2CAA7"));
    assert_eq!(format_record(0x0130, &vec![0x3F,0x01,0x56,0x70,0x2B,0x5E,0x71,0x2B,0x72,0x2B,0x73,0x21,0x46,0x01,0x34,0x21], type_codes::DATA_TYPE_CODE), String::from(":100130003F0156702B5E712B722B732146013421C7"));
    assert_eq!(format_record(0x0000, &[], type_codes::END_OF_FILE_TYPE_CODE), String::from(":00000001FF"));
  }

  #[test]
  fn test_record_as_formatted_string() {
    let eof_record = Record::EndOfFile;
    assert_eq!(eof_record.as_formatted_string(), String::from(":00000001FF"));

    let data_record = Record::Data { address: 0x0100, value: &vec![0x21,0x46,0x01,0x36,0x01,0x21,0x47,0x01,0x36,0x00,0x7E,0xFE,0x09,0xD2,0x19,0x01] };
    assert_eq!(data_record.as_formatted_string(), String::from(":10010000214601360121470136007EFE09D2190140"));
  }

  #[test]
  fn test_i8hex_representation_of_data_ranges_no_ranges() {
    // An empty set of data ranges yields just an EOF marker.
    assert_eq!(i8hex_representation_of_data_ranges(&[]), String::from(":00000001FF"));
  }

  #[test]
  fn test_i8hex_representation_of_data_ranges_one_range() {
    // Build an average-case I8HEX record.
    let mut data_range = DataRange::new(0x100.as_u12().unwrap());
    data_range.append(&vec![0x21,0x46,0x01,0x36,0x01,0x21,0x47,0x01,0x36,0x00,0x7E,0xFE,0x09,0xD2,0x19,0x01]);
    data_range.append(&vec![0x21,0x46,0x01,0x7E,0x17,0xC2,0x00,0x01,0xFF,0x5F,0x16,0x00,0x21,0x48,0x01,0x19]);
    data_range.append(&vec![0x19,0x4E,0x79,0x23,0x46,0x23,0x96,0x57,0x78,0x23,0x9E,0xDA,0x3F,0x01,0xB2,0xCA]);
    data_range.append(&vec![0x3F,0x01,0x56,0x70,0x2B,0x5E,0x71,0x2B,0x72,0x2B,0x73,0x21,0x46,0x01,0x34,0x21]);

    // Validate the average case yielded the anticipated result.
    let i8hex_rep_average = i8hex_representation_of_data_ranges(&[&data_range]);
    let expected_i8hex_rep_average = String::new() +
      &":10010000214601360121470136007EFE09D2190140\n" +
      &":100110002146017E17C20001FF5F16002148011928\n" +
      &":10012000194E79234623965778239EDA3F01B2CAA7\n" +
      &":100130003F0156702B5E712B722B732146013421C7\n" +
      &":00000001FF";
    assert_eq!(i8hex_rep_average, expected_i8hex_rep_average);
  }

  #[test]
  fn test_i8hex_representation_of_data_ranges_adjacent_ranges() {
    // Build an average-case I8HEX record.
    let mut range_a = DataRange::new(0x100.as_u12().unwrap());
    range_a.append(&vec![0x21,0x46,0x01,0x36,0x01,0x21,0x47,0x01,0x36,0x00,0x7E,0xFE,0x09,0xD2,0x19,0x01]);
    let mut range_b = DataRange::new(0x110.as_u12().unwrap());
    range_b.append(&vec![0x21,0x46,0x01,0x7E,0x17,0xC2,0x00,0x01,0xFF,0x5F,0x16,0x00,0x21,0x48,0x01,0x19]);

    // Validate the average case yielded the anticipated result.
    let i8hex_rep_adjacent = i8hex_representation_of_data_ranges(&[&range_a, &range_b]);
    let expected_i8hex_rep_adjacent = String::new() +
      &":10010000214601360121470136007EFE09D2190140\n" +
      &":100110002146017E17C20001FF5F16002148011928\n" +
      &":00000001FF";
    assert_eq!(i8hex_rep_adjacent, expected_i8hex_rep_adjacent);
  }

  #[test]
  fn test_i8hex_representation_of_data_ranges_disjoint_ranges() {
    // Build an average-case I8HEX record.
    let mut range_a = DataRange::new(0x100.as_u12().unwrap());
    range_a.append(&vec![0x21,0x46,0x01,0x36,0x01,0x21,0x47,0x01,0x36,0x00,0x7E,0xFE,0x09,0xD2,0x19,0x01]);
    let mut range_b = DataRange::new(0x130.as_u12().unwrap());
    range_b.append(&vec![0x3F,0x01,0x56,0x70,0x2B,0x5E,0x71,0x2B,0x72,0x2B,0x73,0x21,0x46,0x01,0x34,0x21]);

    // Validate the average case yielded the anticipated result.
    let i8hex_rep_disjoint = i8hex_representation_of_data_ranges(&[&range_a, &range_b]);
    let expected_i8hex_rep_disjoint = String::new() +
      &":10010000214601360121470136007EFE09D2190140\n" +
      &":100130003F0156702B5E712B722B732146013421C7\n" +
      &":00000001FF";
    assert_eq!(i8hex_rep_disjoint, expected_i8hex_rep_disjoint);
  }

  #[test]
  fn test_i8hex_representation_of_data_ranges_uneven_ranges() {
    // Build an average-case I8HEX record.
    let mut range_a = DataRange::new(0x100.as_u12().unwrap());
    range_a.append(&vec![0x21,0x46,0x01,0x36,0x01,0x21,0x47,0x01,0x36,0x00,0x7E,0xFE,0x09,0xD2,0x19]);
    let mut range_b = DataRange::new(0x130.as_u12().unwrap());
    range_b.append(&vec![0x3F,0x01,0x56,0x70,0x2B,0x5E,0x71,0x2B,0x72,0x2B,0x73,0x21,0x46,0x01,0x34,0x21,0x22]);

    // Validate the average case yielded the anticipated result.
    let i8hex_rep = i8hex_representation_of_data_ranges(&[&range_a, &range_b]);
    let expected_i8hex_rep = String::new() +
      &":0F010000214601360121470136007EFE09D21942\n" +
      &":100130003F0156702B5E712B722B732146013421C7\n" +
      &":01014000229C\n" +
      &":00000001FF";
    assert_eq!(i8hex_rep, expected_i8hex_rep);
  }

}
<|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/. */

//#![feature(mpsc_select)]

//! A GPU based Webrender.
//!
//! It serves as an experimental render backend for [Servo](https://servo.org/),
//! but it can also be used as such in a standalone application.
//!
//! # External dependencies
//! Webrender currently depends on [FreeType](https://www.freetype.org/)
//!
//! # Api Structure
//! The main entry point to webrender is the `webrender::renderer::Renderer`.
//!
//! By calling `Renderer::new(...)` you get a `Renderer`, as well as a `RenderApiSender`.
//! Your `Renderer` is responsible to render the previously processed frames onto the screen.
//!
//! By calling `yourRenderApiSenderInstance.create_api()`, you'll get a `RenderApi` instance,
//! which is responsible for the processing of new frames. A worker thread is used internally to
//! untie the workload from the application thread and therefore be able
//! to make better use of multicore systems.
//!
//! What is referred to as a `frame`, is the current geometry on the screen.
//! A new Frame is created by calling [set_root_stacking_context()][newframe] on the `RenderApi`.
//! When the geometry is processed, the application will be informed via a `RenderNotifier`,
//! a callback which you employ with [set_render_notifier][notifier] on the `Renderer`
//! More information about [stacking contexts][stacking_contexts].
//!
//! `set_root_stacking_context()` also needs to be supplied with `BuiltDisplayList`s.
//! These are obtained by finalizing a `DisplayListBuilder`. These are used to draw your geometry.
//! But it doesn't only contain trivial geometry, it can also store another StackingContext, as
//! they're nestable.
//!
//! Remember to insert the DisplayListId into the StackingContext as well, as they'll be referenced
//! from there. An Id for your DisplayList can be obtained by calling
//! `yourRenderApiInstance.next_display_list_id();`
//!
//! [stacking_contexts]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context
//! [newframe]: ../webrender_traits/struct.RenderApi.html#method.set_root_stacking_context
//! [notifier]: struct.Renderer.html#method.set_render_notifier

#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate thread_profiler;

mod batch_builder;
mod clip_scroll_node;
mod clip_scroll_tree;
mod debug_colors;
mod debug_font_data;
mod debug_render;
mod device;
mod frame;
mod frame_builder;
mod freelist;
mod geometry;
mod gpu_store;
mod internal_types;
mod mask_cache;
mod prim_store;
mod profiler;
mod record;
mod render_backend;
mod render_task;
mod resource_cache;
mod scene;
mod spring;
mod texture_cache;
mod tiling;
mod util;

#[cfg(feature = "webgl")]
mod webgl_types;

#[cfg(not(feature = "webgl"))]
#[path = "webgl_stubs.rs"]
mod webgl_types;

mod shader_source {
    include!(concat!(env!("OUT_DIR"), "/shaders.rs"));
}

pub use record::{ApiRecordingReceiver, BinaryRecorder, WEBRENDER_RECORDING_HEADER};

mod platform {
    #[cfg(target_os="macos")]
    pub use platform::macos::font;
    #[cfg(any(target_os = "android", all(unix, not(target_os = "macos"))))]
    pub use platform::unix::font;
    #[cfg(target_os = "windows")]
    pub use platform::windows::font;

    #[cfg(target_os="macos")]
    pub mod macos {
        pub mod font;
    }
    #[cfg(any(target_os = "android", all(unix, not(target_os = "macos"))))]
    pub mod unix {
        pub mod font;
    }
    #[cfg(target_os = "windows")]
    pub mod windows {
        pub mod font;
    }
}

pub mod renderer;

#[cfg(target_os="macos")]
extern crate core_graphics;
#[cfg(target_os="macos")]
extern crate core_text;

#[cfg(all(unix, not(target_os="macos")))]
extern crate freetype;

#[cfg(target_os = "windows")]
extern crate dwrote;

extern crate app_units;
extern crate bincode;
extern crate euclid;
extern crate fnv;
extern crate gleam;
extern crate num_traits;
//extern crate notify;
extern crate time;
extern crate webrender_traits;
#[cfg(feature = "webgl")]
extern crate offscreen_gl_context;
extern crate byteorder;
extern crate threadpool;

#[cfg(any(target_os="macos", target_os="windows"))]
extern crate gamma_lut;

pub use renderer::{ExternalImage, ExternalImageSource, ExternalImageHandler};
pub use renderer::{Renderer, RendererOptions};
<commit_msg>docs: Fix link to set_render_notifier.<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/. */

//#![feature(mpsc_select)]

//! A GPU based Webrender.
//!
//! It serves as an experimental render backend for [Servo](https://servo.org/),
//! but it can also be used as such in a standalone application.
//!
//! # External dependencies
//! Webrender currently depends on [FreeType](https://www.freetype.org/)
//!
//! # Api Structure
//! The main entry point to webrender is the `webrender::renderer::Renderer`.
//!
//! By calling `Renderer::new(...)` you get a `Renderer`, as well as a `RenderApiSender`.
//! Your `Renderer` is responsible to render the previously processed frames onto the screen.
//!
//! By calling `yourRenderApiSenderInstance.create_api()`, you'll get a `RenderApi` instance,
//! which is responsible for the processing of new frames. A worker thread is used internally to
//! untie the workload from the application thread and therefore be able
//! to make better use of multicore systems.
//!
//! What is referred to as a `frame`, is the current geometry on the screen.
//! A new Frame is created by calling [set_root_stacking_context()][newframe] on the `RenderApi`.
//! When the geometry is processed, the application will be informed via a `RenderNotifier`,
//! a callback which you employ with [set_render_notifier][notifier] on the `Renderer`
//! More information about [stacking contexts][stacking_contexts].
//!
//! `set_root_stacking_context()` also needs to be supplied with `BuiltDisplayList`s.
//! These are obtained by finalizing a `DisplayListBuilder`. These are used to draw your geometry.
//! But it doesn't only contain trivial geometry, it can also store another StackingContext, as
//! they're nestable.
//!
//! Remember to insert the DisplayListId into the StackingContext as well, as they'll be referenced
//! from there. An Id for your DisplayList can be obtained by calling
//! `yourRenderApiInstance.next_display_list_id();`
//!
//! [stacking_contexts]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context
//! [newframe]: ../webrender_traits/struct.RenderApi.html#method.set_root_stacking_context
//! [notifier]: renderer/struct.Renderer.html#method.set_render_notifier

#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate thread_profiler;

mod batch_builder;
mod clip_scroll_node;
mod clip_scroll_tree;
mod debug_colors;
mod debug_font_data;
mod debug_render;
mod device;
mod frame;
mod frame_builder;
mod freelist;
mod geometry;
mod gpu_store;
mod internal_types;
mod mask_cache;
mod prim_store;
mod profiler;
mod record;
mod render_backend;
mod render_task;
mod resource_cache;
mod scene;
mod spring;
mod texture_cache;
mod tiling;
mod util;

#[cfg(feature = "webgl")]
mod webgl_types;

#[cfg(not(feature = "webgl"))]
#[path = "webgl_stubs.rs"]
mod webgl_types;

mod shader_source {
    include!(concat!(env!("OUT_DIR"), "/shaders.rs"));
}

pub use record::{ApiRecordingReceiver, BinaryRecorder, WEBRENDER_RECORDING_HEADER};

mod platform {
    #[cfg(target_os="macos")]
    pub use platform::macos::font;
    #[cfg(any(target_os = "android", all(unix, not(target_os = "macos"))))]
    pub use platform::unix::font;
    #[cfg(target_os = "windows")]
    pub use platform::windows::font;

    #[cfg(target_os="macos")]
    pub mod macos {
        pub mod font;
    }
    #[cfg(any(target_os = "android", all(unix, not(target_os = "macos"))))]
    pub mod unix {
        pub mod font;
    }
    #[cfg(target_os = "windows")]
    pub mod windows {
        pub mod font;
    }
}

pub mod renderer;

#[cfg(target_os="macos")]
extern crate core_graphics;
#[cfg(target_os="macos")]
extern crate core_text;

#[cfg(all(unix, not(target_os="macos")))]
extern crate freetype;

#[cfg(target_os = "windows")]
extern crate dwrote;

extern crate app_units;
extern crate bincode;
extern crate euclid;
extern crate fnv;
extern crate gleam;
extern crate num_traits;
//extern crate notify;
extern crate time;
extern crate webrender_traits;
#[cfg(feature = "webgl")]
extern crate offscreen_gl_context;
extern crate byteorder;
extern crate threadpool;

#[cfg(any(target_os="macos", target_os="windows"))]
extern crate gamma_lut;

pub use renderer::{ExternalImage, ExternalImageSource, ExternalImageHandler};
pub use renderer::{Renderer, RendererOptions};
<|endoftext|>


<commit_before>#![crate_id="cargo-git-checkout"]

extern crate cargo;
extern crate serialize;
extern crate hammer;
extern crate url;

use hammer::FlagConfig;
use cargo::{execute_main_without_stdin,CLIResult,CLIError,ToResult};
use cargo::sources::git::{GitRemote,GitCheckout};
use url::Url;

#[deriving(Eq,Clone,Decodable)]
struct Options {
    database_path: String,
    checkout_path: String,
    url: String,
    reference: String,
    verbose: bool
}

impl FlagConfig for Options {}

fn main() {
    execute_main_without_stdin(execute);
}

fn execute(options: Options) -> CLIResult<Option<GitCheckout>> {
    let Options { database_path, checkout_path, url, reference, verbose } = options;

    let url: Url = try!(from_str(url.as_slice()).to_result(|_|
        CLIError::new(format!("The URL `{}` you passed was not a valid URL", url), None::<&str>, 1)));

    let repo = GitRemote::new(url, verbose);
    let local = try!(repo.checkout(&Path::new(database_path)).map_err(|e|
        CLIError::new(format!("Couldn't check out repository: {}", e), None::<&str>, 1)));

    let checkout = try!(local.copy_to(reference, &Path::new(checkout_path)).map_err(|e|
        CLIError::new(format!("Couldn't copy repository: {}", e), None::<&str>, 1)));

    Ok(Some(checkout))
}
<commit_msg>Use GitSource in the stub executable<commit_after>#![crate_id="cargo-git-checkout"]

extern crate cargo;
extern crate serialize;
extern crate hammer;
extern crate url;

use hammer::FlagConfig;
use cargo::{execute_main_without_stdin,CLIResult,CLIError,ToResult};
use cargo::core::source::Source;
use cargo::sources::git::{GitSource,GitRemote};
use url::Url;

#[deriving(Eq,Clone,Decodable)]
struct Options {
    database_path: String,
    checkout_path: String,
    url: String,
    reference: String,
    verbose: bool
}

impl FlagConfig for Options {}

fn main() {
    execute_main_without_stdin(execute);
}

fn execute(options: Options) -> CLIResult<Option<()>> {
    let Options { database_path, checkout_path, url, reference, verbose } = options;

    let url: Url = try!(from_str(url.as_slice()).to_result(|_|
        CLIError::new(format!("The URL `{}` you passed was not a valid URL", url), None::<&str>, 1)));

    let remote = GitRemote::new(url, verbose);
    let source = GitSource::new(remote, reference, Path::new(database_path), Path::new(checkout_path), verbose);
    try!(source.update().map_err(|e| {
        CLIError::new(format!("Couldn't update {}: {}", source, e), None::<&str>, 1)
    }));

    Ok(None)
}
<|endoftext|>


<commit_before>use command_prelude::*;

use cargo::ops::{self, DocOptions};

pub fn cli() -> App {
    subcommand("doc")
        .about("Build a package's documentation")
        .arg(opt(
            "open",
            "Opens the docs in a browser after the operation",
        ))
        .arg_package_spec(
            "Package to document",
            "Document all packages in the workspace",
            "Exclude packages from the build",
        )
        .arg(opt("no-deps", "Don't build documentation for dependencies"))
        .arg_jobs()
        .arg_targets_lib_bin(
            "Document only this package's library",
            "Document only the specified binary",
            "Document all binaries",
        )
        .arg_release("Build artifacts in release mode, with optimizations")
        .arg_features()
        .arg_target_triple("Build for the target triple")
        .arg_target_dir()
        .arg_manifest_path()
        .arg_message_format()
        .after_help(
            "\
By default the documentation for the local package and all dependencies is
built. The output is all placed in `target/doc` in rustdoc's usual format.

All packages in the workspace are documented if the `--all` flag is supplied. The
`--all` flag is automatically assumed for a virtual manifest.
Note that `--exclude` has to be specified in conjunction with the `--all` flag.

If the --package argument is given, then SPEC is a package id specification
which indicates which package should be documented. If it is not given, then the
current package is documented. For more information on SPEC and its format, see
the `cargo help pkgid` command.
",
        )
}

pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
    let ws = args.workspace(config)?;
    let mode = CompileMode::Doc {
        deps: !args.is_present("no-deps"),
    };
    let compile_opts = args.compile_options(config, mode)?;
    let doc_opts = DocOptions {
        open_result: args.is_present("open"),
        compile_opts,
    };
    ops::doc(&ws, &doc_opts)?;
    Ok(())
}
<commit_msg>Add document-private-items flag to cargo doc<commit_after>use command_prelude::*;

use cargo::ops::{self, DocOptions};

pub fn cli() -> App {
    subcommand("doc")
        .about("Build a package's documentation")
        .arg(opt(
            "open",
            "Opens the docs in a browser after the operation",
        ))
        .arg_package_spec(
            "Package to document",
            "Document all packages in the workspace",
            "Exclude packages from the build",
        )
        .arg(opt("no-deps", "Don't build documentation for dependencies"))
        .arg(opt("document-private-items", "Document private items"))
        .arg_jobs()
        .arg_targets_lib_bin(
            "Document only this package's library",
            "Document only the specified binary",
            "Document all binaries",
        )
        .arg_release("Build artifacts in release mode, with optimizations")
        .arg_features()
        .arg_target_triple("Build for the target triple")
        .arg_target_dir()
        .arg_manifest_path()
        .arg_message_format()
        .after_help(
            "\
By default the documentation for the local package and all dependencies is
built. The output is all placed in `target/doc` in rustdoc's usual format.

All packages in the workspace are documented if the `--all` flag is supplied. The
`--all` flag is automatically assumed for a virtual manifest.
Note that `--exclude` has to be specified in conjunction with the `--all` flag.

If the --package argument is given, then SPEC is a package id specification
which indicates which package should be documented. If it is not given, then the
current package is documented. For more information on SPEC and its format, see
the `cargo help pkgid` command.
",
        )
}

pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
    let ws = args.workspace(config)?;
    let mode = CompileMode::Doc {
        deps: !args.is_present("no-deps"),
    };
    let mut compile_opts = args.compile_options(config, mode)?;
    compile_opts.target_rustdoc_args = if args.is_present("document-private-items") {
        Some(vec!["--document-private-items".to_string()])
    } else {
        None
    };
    let doc_opts = DocOptions {
        open_result: args.is_present("open"),
        compile_opts,
    };
    ops::doc(&ws, &doc_opts)?;
    Ok(())
}
<|endoftext|>


<commit_before>#[link(name="socketlib", vers="0.0")];

mod socket {

export socket_handle;

class socket_handle {
    let sockfd: libc::c_int;
    new(x: libc::c_int) {self.sockfd = x;}
    drop { /* c::close(self.sockfd); */ }
}
}
<commit_msg>Attempt to get issue 3012 test working on win32.<commit_after>#[link(name="socketlib", vers="0.0")];
#[crate_type = "lib"];

mod socket {

export socket_handle;

class socket_handle {
    let sockfd: libc::c_int;
    new(x: libc::c_int) {self.sockfd = x;}
    drop { /* c::close(self.sockfd); */ }
}
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::HashMap;
use std::time::Duration;

use serialport as sp;
use serial_support::errors::*;

/// Struct for containing Port information
struct OpenPort {
  /// The opened serial port
  /// SerialPort is not Sized, so it makes hashmap mad
  /// and so we deal with these shennanigans
  port: RefCell<Box<sp::SerialPort>>,
}

impl OpenPort {
  /// Write data to the serial port
  pub fn write_port(&self, data: &[u8]) -> Result<()> {
    self
      .port
      .borrow_mut()
      .write_all(data)
      .map_err(|err| ErrorKind::Io(err).into())
  }
  /// Read data from the serial port
  pub fn read_port(&self, buff: &mut [u8]) -> Result<usize> {
    self
      .port
      .borrow_mut()
      .read(buff)
      .map_err(|err| ErrorKind::Io(err).into())
  }
}

/// Manages ports and their locks
pub struct PortManager {
  /// Maintains list of ports
  open_ports: HashMap<String, OpenPort>,
}

impl PortManager {
  /// Create a new PortManager instance
  pub fn new() -> PortManager {
    PortManager { open_ports: HashMap::new() }
  }

  /// Has the port been opened
  pub fn is_port_open(&self, port_name: &String) -> bool {
    self.open_ports.contains_key(port_name)
  }

  /// Open a port
  pub fn open_port(&mut self, port_name: &String) -> Result<()> {

    if self.is_port_open(port_name) {
      Ok(())
    } else {

      let sp_settings = sp::SerialPortSettings {
        baud_rate: sp::BaudRate::Baud115200,
        data_bits: sp::DataBits::Eight,
        flow_control: sp::FlowControl::None,
        parity: sp::Parity::None,
        stop_bits: sp::StopBits::One,
        timeout: Duration::from_millis(1),
      };

      match sp::open_with_settings(&port_name, &sp_settings) {
        Ok(serial_port) => {
          let open_port = OpenPort { port: RefCell::new(serial_port) };
          self.open_ports.insert(port_name.to_string(), open_port);
          Ok(())
        }
        Err(e) => Err(ErrorKind::Serialport(e).into()),
      }
    }
  }

  pub fn close_port(&mut self, port_name: &String) {
    // This drops the underlying serial port and box
    self.open_ports.remove(port_name);
  }

  /// Write data to the port
  /// To write data to a port the port must have been previously locked by sub_id
  pub fn write_port(&self, port_name: &String, data: &[u8]) -> Result<()> {
    match self.open_ports.get(port_name) {
      None => Err(ErrorKind::OpenPortNotFound(port_name.to_string()).into()),
      Some(p) => p.write_port(data),
    }
  }

  /// Read data from a port into the buffer buff
  /// If successful, returns Ok(usize) which is the number of
  /// bytes read
  pub fn read_port(&self, port_name: &String, buff: &mut [u8]) -> Result<usize> {
    match self.open_ports.get(port_name) {
      None => Err(ErrorKind::OpenPortNotFound(port_name.to_string()).into()),
      Some(p) => p.read_port(buff),
    }
  }

  /// Read all currently open ports, return a hashmap of
  /// ports to Result<Vec<u8>>
  pub fn read_all_ports(&self) -> HashMap<String, Result<Vec<u8>>> {
    let mut buffer = vec![0; 4096];
    let mut map = HashMap::new();
    for port_name in self.open_ports.keys() {
      match self.read_port(port_name, buffer.as_mut_slice()) {
        Ok(bytes_read) => {
          let bytes = buffer[0..bytes_read].to_vec();
          map.insert(port_name.to_string(), Ok(bytes));
        }
        Err(e) => {
          map.insert(port_name.to_string(),
                     Err(ErrorKind::PortReadError(port_name.to_string()).into()));
        }
      }
    }
    map
  }

  /// Get a vec of open ports
  pub fn open_ports(&self) -> Vec<String> {
    let mut open_ports = Vec::<String>::new();
    for port_name in self.open_ports.keys() {
      open_ports.push(port_name.clone());
    }
    open_ports
  }
}
<commit_msg>Ensure we send the underlying error<commit_after>use std::cell::RefCell;
use std::collections::HashMap;
use std::time::Duration;

use serialport as sp;
use serial_support::errors::*;

/// Struct for containing Port information
struct OpenPort {
  /// The opened serial port
  /// SerialPort is not Sized, so it makes hashmap mad
  /// and so we deal with these shennanigans
  port: RefCell<Box<sp::SerialPort>>,
}

impl OpenPort {
  /// Write data to the serial port
  pub fn write_port(&self, data: &[u8]) -> Result<()> {
    self
      .port
      .borrow_mut()
      .write_all(data)
      .map_err(|err| ErrorKind::Io(err).into())
  }
  /// Read data from the serial port
  pub fn read_port(&self, buff: &mut [u8]) -> Result<usize> {
    self
      .port
      .borrow_mut()
      .read(buff)
      .map_err(|err| ErrorKind::Io(err).into())
  }
}

/// Manages ports and their locks
pub struct PortManager {
  /// Maintains list of ports
  open_ports: HashMap<String, OpenPort>,
}

impl PortManager {
  /// Create a new PortManager instance
  pub fn new() -> PortManager {
    PortManager { open_ports: HashMap::new() }
  }

  /// Has the port been opened
  pub fn is_port_open(&self, port_name: &String) -> bool {
    self.open_ports.contains_key(port_name)
  }

  /// Open a port
  pub fn open_port(&mut self, port_name: &String) -> Result<()> {

    if self.is_port_open(port_name) {
      Ok(())
    } else {

      let sp_settings = sp::SerialPortSettings {
        baud_rate: sp::BaudRate::Baud115200,
        data_bits: sp::DataBits::Eight,
        flow_control: sp::FlowControl::None,
        parity: sp::Parity::None,
        stop_bits: sp::StopBits::One,
        timeout: Duration::from_millis(1),
      };

      match sp::open_with_settings(&port_name, &sp_settings) {
        Ok(serial_port) => {
          let open_port = OpenPort { port: RefCell::new(serial_port) };
          self.open_ports.insert(port_name.to_string(), open_port);
          Ok(())
        }
        Err(e) => Err(ErrorKind::Serialport(e).into()),
      }
    }
  }

  pub fn close_port(&mut self, port_name: &String) {
    // This drops the underlying serial port and box
    self.open_ports.remove(port_name);
  }

  /// Write data to the port
  /// To write data to a port the port must have been previously locked by sub_id
  pub fn write_port(&self, port_name: &String, data: &[u8]) -> Result<()> {
    match self.open_ports.get(port_name) {
      None => Err(ErrorKind::OpenPortNotFound(port_name.to_string()).into()),
      Some(p) => p.write_port(data),
    }
  }

  /// Read data from a port into the buffer buff
  /// If successful, returns Ok(usize) which is the number of
  /// bytes read
  pub fn read_port(&self, port_name: &String, buff: &mut [u8]) -> Result<usize> {
    match self.open_ports.get(port_name) {
      None => Err(ErrorKind::OpenPortNotFound(port_name.to_string()).into()),
      Some(p) => p.read_port(buff),
    }
  }

  /// Read all currently open ports, return a hashmap of
  /// ports to Result<Vec<u8>>
  pub fn read_all_ports(&self) -> HashMap<String, Result<Vec<u8>>> {
    let mut buffer = vec![0; 4096];
    let mut map = HashMap::new();
    for port_name in self.open_ports.keys() {
      match self.read_port(port_name, buffer.as_mut_slice()) {
        Ok(bytes_read) => {
          let bytes = buffer[0..bytes_read].to_vec();
          map.insert(port_name.to_string(), Ok(bytes));
        }
        Err(e) => {
          map.insert(port_name.to_string(),
                     Err(e.into()));
        }
      }
    }
    map
  }

  /// Get a vec of open ports
  pub fn open_ports(&self) -> Vec<String> {
    let mut open_ports = Vec::<String>::new();
    for port_name in self.open_ports.keys() {
      open_ports.push(port_name.clone());
    }
    open_ports
  }
}
<|endoftext|>


<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.

// compile-flags: -Z span_free_formats

// Tests that MIR inliner can handle closure arguments. (#45894)

fn main() {
    println!("{}", foo(0, 14));
}

fn foo<T: Copy>(_t: T, q: i32) -> i32 {
    let x = |_t, _q| _t;
    x(q*2, q*3)
}

// END RUST SOURCE
// START rustc.foo.Inline.after.mir
// ...
// bb0: {
//     StorageLive(_3);
//     _3 = [closure@NodeId(28)];
//     StorageLive(_4);
//     _4 = &_3;
//     StorageLive(_5);
//     StorageLive(_6);
//     StorageLive(_7);
//     _7 = _2;
//     _6 = Mul(_7, const 2i32);
//     StorageDead(_7);
//     StorageLive(_8);
//     StorageLive(_9);
//     _9 = _2;
//     _8 = Mul(_9, const 3i32);
//     StorageDead(_9);
//     _5 = (_6, _8);
//     _0 = (_5.0: i32);
//     StorageDead(_5);
//     StorageDead(_8);
//     StorageDead(_6);
//     StorageDead(_4);
//     StorageDead(_3);
//     return;
// }
// ...
// END rustc.foo.Inline.after.mir<commit_msg>Fix test<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.

// compile-flags: -Z span_free_formats

// Tests that MIR inliner can handle closure arguments. (#45894)

fn main() {
    println!("{}", foo(0, 14));
}

fn foo<T: Copy>(_t: T, q: i32) -> i32 {
    let x = |_t, _q| _t;
    x(q, q)
}

// END RUST SOURCE
// START rustc.foo.Inline.after.mir
// ...
// bb0: {
//     ...
//     _3 = [closure@NodeId(28)];
//     ...
//     _4 = &_3;
//     ...
//     _6 = _2;
//     ...
//     _7 = _2;
//     _5 = (_6, _7);
//     _0 = (_5.0: i32);
//     ...
//     return;
// }
// ...
// END rustc.foo.Inline.after.mir<|endoftext|>


<commit_before>
use std;
import std::vec;

fn main() {
    let v = [1, 2, 3];
    log_err vec::refcount[int](v);
    log_err vec::refcount[int](v);
    log_err vec::refcount[int](v);
    assert (vec::refcount[int](v) == 1u || vec::refcount[int](v) == 2u);
    assert (vec::refcount[int](v) == 1u || vec::refcount[int](v) == 2u);
}<commit_msg>Remove run-pass/vec-ref-count.rs<commit_after><|endoftext|>


<commit_before>use std::{
    cell::RefCell,
    ops::Deref as _,
    rc::Rc,
    sync::{
        atomic::{AtomicBool, Ordering},
        Mutex,
    },
};

use wayland_server::{
    protocol::{wl_compositor, wl_region, wl_subcompositor, wl_subsurface, wl_surface},
    DispatchData, Filter, Main,
};

use crate::utils::{Logical, Point};

use super::{
    cache::Cacheable,
    tree::{Location, PrivateSurfaceData},
    AlreadyHasRole, BufferAssignment, Damage, Rectangle, RectangleKind, RegionAttributes, SurfaceAttributes,
};

use slog::trace;

/*
 * wl_compositor
 */

pub(crate) fn implement_compositor<Impl>(
    compositor: Main<wl_compositor::WlCompositor>,
    log: ::slog::Logger,
    implem: Rc<RefCell<Impl>>,
) -> wl_compositor::WlCompositor
where
    Impl: for<'a> FnMut(wl_surface::WlSurface, DispatchData<'a>) + 'static,
{
    compositor.quick_assign(move |_compositor, request, _| match request {
        wl_compositor::Request::CreateSurface { id } => {
            trace!(log, "Creating a new wl_surface.");
            implement_surface(id, log.clone(), implem.clone());
        }
        wl_compositor::Request::CreateRegion { id } => {
            trace!(log, "Creating a new wl_region.");
            implement_region(id);
        }
        _ => unreachable!(),
    });
    compositor.deref().clone()
}

/*
 * wl_surface
 */

type SurfaceImplemFn = dyn for<'a> FnMut(wl_surface::WlSurface, DispatchData<'a>);

// Internal implementation data of surfaces
pub(crate) struct SurfaceImplem {
    log: ::slog::Logger,
    implem: Rc<RefCell<SurfaceImplemFn>>,
}

impl SurfaceImplem {
    fn make<Impl>(log: ::slog::Logger, implem: Rc<RefCell<Impl>>) -> SurfaceImplem
    where
        Impl: for<'a> FnMut(wl_surface::WlSurface, DispatchData<'a>) + 'static,
    {
        SurfaceImplem { log, implem }
    }
}

impl SurfaceImplem {
    fn receive_surface_request(
        &mut self,
        req: wl_surface::Request,
        surface: wl_surface::WlSurface,
        ddata: DispatchData<'_>,
    ) {
        match req {
            wl_surface::Request::Attach { buffer, x, y } => {
                PrivateSurfaceData::with_states(&surface, |states| {
                    states.cached_state.pending::<SurfaceAttributes>().buffer = Some(match buffer {
                        Some(buffer) => BufferAssignment::NewBuffer {
                            buffer,
                            delta: (x, y).into(),
                        },
                        None => BufferAssignment::Removed,
                    })
                });
            }
            wl_surface::Request::Damage { x, y, width, height } => {
                PrivateSurfaceData::with_states(&surface, |states| {
                    states
                        .cached_state
                        .pending::<SurfaceAttributes>()
                        .damage
                        .push(Damage::Surface(Rectangle::from_loc_and_size(
                            (x, y),
                            (width, height),
                        )));
                });
            }
            wl_surface::Request::Frame { callback } => {
                PrivateSurfaceData::with_states(&surface, |states| {
                    states
                        .cached_state
                        .pending::<SurfaceAttributes>()
                        .frame_callbacks
                        .push((*callback).clone());
                });
            }
            wl_surface::Request::SetOpaqueRegion { region } => {
                let attributes = region.map(|r| {
                    let attributes_mutex = r.as_ref().user_data().get::<Mutex<RegionAttributes>>().unwrap();
                    attributes_mutex.lock().unwrap().clone()
                });
                PrivateSurfaceData::with_states(&surface, |states| {
                    states.cached_state.pending::<SurfaceAttributes>().opaque_region = attributes;
                });
            }
            wl_surface::Request::SetInputRegion { region } => {
                let attributes = region.map(|r| {
                    let attributes_mutex = r.as_ref().user_data().get::<Mutex<RegionAttributes>>().unwrap();
                    attributes_mutex.lock().unwrap().clone()
                });
                PrivateSurfaceData::with_states(&surface, |states| {
                    states.cached_state.pending::<SurfaceAttributes>().input_region = attributes;
                });
            }
            wl_surface::Request::Commit => {
                let mut user_impl = self.implem.borrow_mut();
                PrivateSurfaceData::invoke_commit_hooks(&surface);
                if !surface.as_ref().is_alive() {
                    // the client was killed by a hook, abort
                    return;
                }
                PrivateSurfaceData::commit(&surface);
                trace!(self.log, "Calling user implementation for wl_surface.commit");
                (&mut *user_impl)(surface, ddata);
            }
            wl_surface::Request::SetBufferTransform { transform } => {
                PrivateSurfaceData::with_states(&surface, |states| {
                    states
                        .cached_state
                        .pending::<SurfaceAttributes>()
                        .buffer_transform = transform;
                });
            }
            wl_surface::Request::SetBufferScale { scale } => {
                PrivateSurfaceData::with_states(&surface, |states| {
                    states.cached_state.pending::<SurfaceAttributes>().buffer_scale = scale;
                });
            }
            wl_surface::Request::DamageBuffer { x, y, width, height } => {
                PrivateSurfaceData::with_states(&surface, |states| {
                    states
                        .cached_state
                        .pending::<SurfaceAttributes>()
                        .damage
                        .push(Damage::Buffer(Rectangle::from_loc_and_size(
                            (x, y),
                            (width, height),
                        )))
                });
            }
            wl_surface::Request::Destroy => {
                // All is already handled by our destructor
            }
            _ => unreachable!(),
        }
    }
}

impl Cacheable for SurfaceAttributes {
    fn commit(&mut self) -> Self {
        SurfaceAttributes {
            buffer: self.buffer.take(),
            buffer_scale: self.buffer_scale,
            buffer_transform: self.buffer_transform,
            damage: std::mem::take(&mut self.damage),
            opaque_region: self.opaque_region.clone(),
            input_region: self.input_region.clone(),
            frame_callbacks: std::mem::take(&mut self.frame_callbacks),
        }
    }
    fn merge_into(self, into: &mut Self) {
        if self.buffer.is_some() {
            if let Some(BufferAssignment::NewBuffer { buffer, .. }) =
                std::mem::replace(&mut into.buffer, self.buffer)
            {
                let new_buffer = into.buffer.as_ref().and_then(|b| match b {
                    BufferAssignment::Removed => None,
                    BufferAssignment::NewBuffer { buffer, .. } => Some(buffer),
                });

                if Some(&buffer) != new_buffer {
                    buffer.release();
                }
            }
        }
        into.buffer_scale = self.buffer_scale;
        into.buffer_transform = self.buffer_transform;
        into.damage.extend(self.damage);
        into.opaque_region = self.opaque_region;
        into.input_region = self.input_region;
        into.frame_callbacks.extend(self.frame_callbacks);
    }
}

fn implement_surface<Impl>(
    surface: Main<wl_surface::WlSurface>,
    log: ::slog::Logger,
    implem: Rc<RefCell<Impl>>,
) -> wl_surface::WlSurface
where
    Impl: for<'a> FnMut(wl_surface::WlSurface, DispatchData<'a>) + 'static,
{
    surface.quick_assign({
        let mut implem = SurfaceImplem::make(log, implem);
        move |surface, req, ddata| implem.receive_surface_request(req, surface.deref().clone(), ddata)
    });
    surface.assign_destructor(Filter::new(|surface, _, _| PrivateSurfaceData::cleanup(&surface)));
    surface
        .as_ref()
        .user_data()
        .set_threadsafe(PrivateSurfaceData::new);
    PrivateSurfaceData::init(&surface);
    surface.deref().clone()
}

/*
 * wl_region
 */

fn region_implem(request: wl_region::Request, region: wl_region::WlRegion) {
    let attributes_mutex = region
        .as_ref()
        .user_data()
        .get::<Mutex<RegionAttributes>>()
        .unwrap();
    let mut guard = attributes_mutex.lock().unwrap();
    match request {
        wl_region::Request::Add { x, y, width, height } => guard.rects.push((
            RectangleKind::Add,
            Rectangle::from_loc_and_size((x, y), (width, height)),
        )),
        wl_region::Request::Subtract { x, y, width, height } => guard.rects.push((
            RectangleKind::Subtract,
            Rectangle::from_loc_and_size((x, y), (width, height)),
        )),
        wl_region::Request::Destroy => {
            // all is handled by our destructor
        }
        _ => unreachable!(),
    }
}

fn implement_region(region: Main<wl_region::WlRegion>) -> wl_region::WlRegion {
    region.quick_assign(|region, req, _| region_implem(req, region.deref().clone()));
    region
        .as_ref()
        .user_data()
        .set_threadsafe(|| Mutex::new(RegionAttributes::default()));
    region.deref().clone()
}

/*
 * wl_subcompositor
 */

pub(crate) fn implement_subcompositor(
    subcompositor: Main<wl_subcompositor::WlSubcompositor>,
) -> wl_subcompositor::WlSubcompositor {
    subcompositor.quick_assign(move |subcompositor, request, _| match request {
        wl_subcompositor::Request::GetSubsurface { id, surface, parent } => {
            if let Err(AlreadyHasRole) = PrivateSurfaceData::set_parent(&surface, &parent) {
                subcompositor.as_ref().post_error(
                    wl_subcompositor::Error::BadSurface as u32,
                    "Surface already has a role.".into(),
                );
                return;
            }
            implement_subsurface(id, surface);
        }
        wl_subcompositor::Request::Destroy => {}
        _ => unreachable!(),
    });
    subcompositor.deref().clone()
}

/*
 * wl_subsurface
 */

/// The cached state associated with a subsurface
#[derive(Debug)]
pub struct SubsurfaceCachedState {
    /// Location of the top-left corner of this subsurface
    /// relative to its parent coordinate space
    pub location: Point<i32, Logical>,
}

impl Default for SubsurfaceCachedState {
    fn default() -> Self {
        SubsurfaceCachedState {
            location: (0, 0).into(),
        }
    }
}

impl Cacheable for SubsurfaceCachedState {
    fn commit(&mut self) -> Self {
        SubsurfaceCachedState {
            location: self.location,
        }
    }

    fn merge_into(self, into: &mut Self) {
        into.location = self.location;
    }
}

pub(crate) struct SubsurfaceState {
    pub(crate) sync: AtomicBool,
}

impl SubsurfaceState {
    fn new() -> SubsurfaceState {
        SubsurfaceState {
            sync: AtomicBool::new(true),
        }
    }
}

/// Check if a (sub)surface is effectively sync
pub fn is_effectively_sync(surface: &wl_surface::WlSurface) -> bool {
    let is_direct_sync = PrivateSurfaceData::with_states(surface, |state| {
        state
            .data_map
            .get::<SubsurfaceState>()
            .map(|s| s.sync.load(Ordering::Acquire))
            .unwrap_or(false)
    });
    if is_direct_sync {
        return true;
    }
    if let Some(parent) = PrivateSurfaceData::get_parent(surface) {
        is_effectively_sync(&parent)
    } else {
        false
    }
}

fn implement_subsurface(
    subsurface: Main<wl_subsurface::WlSubsurface>,
    surface: wl_surface::WlSurface,
) -> wl_subsurface::WlSubsurface {
    let data_surface = surface.clone();
    subsurface.quick_assign(move |subsurface, request, _| {
        match request {
            wl_subsurface::Request::SetPosition { x, y } => {
                PrivateSurfaceData::with_states(&surface, |state| {
                    state.cached_state.pending::<SubsurfaceCachedState>().location = (x, y).into();
                })
            }
            wl_subsurface::Request::PlaceAbove { sibling } => {
                let surface = subsurface
                    .as_ref()
                    .user_data()
                    .get::<wl_surface::WlSurface>()
                    .unwrap();
                if let Err(()) = PrivateSurfaceData::reorder(surface, Location::After, &sibling) {
                    subsurface.as_ref().post_error(
                        wl_subsurface::Error::BadSurface as u32,
                        "Provided surface is not a sibling or parent.".into(),
                    )
                }
            }
            wl_subsurface::Request::PlaceBelow { sibling } => {
                let surface = subsurface
                    .as_ref()
                    .user_data()
                    .get::<wl_surface::WlSurface>()
                    .unwrap();
                if let Err(()) = PrivateSurfaceData::reorder(surface, Location::Before, &sibling) {
                    subsurface.as_ref().post_error(
                        wl_subsurface::Error::BadSurface as u32,
                        "Provided surface is not a sibling or parent.".into(),
                    )
                }
            }
            wl_subsurface::Request::SetSync => PrivateSurfaceData::with_states(&surface, |state| {
                state
                    .data_map
                    .get::<SubsurfaceState>()
                    .unwrap()
                    .sync
                    .store(true, Ordering::Release);
            }),
            wl_subsurface::Request::SetDesync => PrivateSurfaceData::with_states(&surface, |state| {
                state
                    .data_map
                    .get::<SubsurfaceState>()
                    .unwrap()
                    .sync
                    .store(false, Ordering::Release);
            }),
            wl_subsurface::Request::Destroy => {
                // Our destructor already handles it
            }
            _ => unreachable!(),
        }
    });
    super::with_states(&data_surface, |states| {
        states.data_map.insert_if_missing_threadsafe(SubsurfaceState::new)
    })
    .unwrap();
    subsurface.assign_destructor(Filter::new(|subsurface, _, _| destroy_subsurface(&subsurface)));
    subsurface
        .as_ref()
        .user_data()
        .set_threadsafe(move || data_surface);
    subsurface.deref().clone()
}

fn destroy_subsurface(subsurface: &wl_subsurface::WlSubsurface) {
    let surface = subsurface
        .as_ref()
        .user_data()
        .get::<wl_surface::WlSurface>()
        .unwrap();
    if surface.as_ref().is_alive() {
        PrivateSurfaceData::unset_parent(surface);
    }
}
<commit_msg>clear the surface damage if a surface got unmapped<commit_after>use std::{
    cell::RefCell,
    ops::Deref as _,
    rc::Rc,
    sync::{
        atomic::{AtomicBool, Ordering},
        Mutex,
    },
};

use wayland_server::{
    protocol::{wl_compositor, wl_region, wl_subcompositor, wl_subsurface, wl_surface},
    DispatchData, Filter, Main,
};

use crate::utils::{Logical, Point};

use super::{
    cache::Cacheable,
    tree::{Location, PrivateSurfaceData},
    AlreadyHasRole, BufferAssignment, Damage, Rectangle, RectangleKind, RegionAttributes, SurfaceAttributes,
};

use slog::trace;

/*
 * wl_compositor
 */

pub(crate) fn implement_compositor<Impl>(
    compositor: Main<wl_compositor::WlCompositor>,
    log: ::slog::Logger,
    implem: Rc<RefCell<Impl>>,
) -> wl_compositor::WlCompositor
where
    Impl: for<'a> FnMut(wl_surface::WlSurface, DispatchData<'a>) + 'static,
{
    compositor.quick_assign(move |_compositor, request, _| match request {
        wl_compositor::Request::CreateSurface { id } => {
            trace!(log, "Creating a new wl_surface.");
            implement_surface(id, log.clone(), implem.clone());
        }
        wl_compositor::Request::CreateRegion { id } => {
            trace!(log, "Creating a new wl_region.");
            implement_region(id);
        }
        _ => unreachable!(),
    });
    compositor.deref().clone()
}

/*
 * wl_surface
 */

type SurfaceImplemFn = dyn for<'a> FnMut(wl_surface::WlSurface, DispatchData<'a>);

// Internal implementation data of surfaces
pub(crate) struct SurfaceImplem {
    log: ::slog::Logger,
    implem: Rc<RefCell<SurfaceImplemFn>>,
}

impl SurfaceImplem {
    fn make<Impl>(log: ::slog::Logger, implem: Rc<RefCell<Impl>>) -> SurfaceImplem
    where
        Impl: for<'a> FnMut(wl_surface::WlSurface, DispatchData<'a>) + 'static,
    {
        SurfaceImplem { log, implem }
    }
}

impl SurfaceImplem {
    fn receive_surface_request(
        &mut self,
        req: wl_surface::Request,
        surface: wl_surface::WlSurface,
        ddata: DispatchData<'_>,
    ) {
        match req {
            wl_surface::Request::Attach { buffer, x, y } => {
                PrivateSurfaceData::with_states(&surface, |states| {
                    states.cached_state.pending::<SurfaceAttributes>().buffer = Some(match buffer {
                        Some(buffer) => BufferAssignment::NewBuffer {
                            buffer,
                            delta: (x, y).into(),
                        },
                        None => BufferAssignment::Removed,
                    })
                });
            }
            wl_surface::Request::Damage { x, y, width, height } => {
                PrivateSurfaceData::with_states(&surface, |states| {
                    states
                        .cached_state
                        .pending::<SurfaceAttributes>()
                        .damage
                        .push(Damage::Surface(Rectangle::from_loc_and_size(
                            (x, y),
                            (width, height),
                        )));
                });
            }
            wl_surface::Request::Frame { callback } => {
                PrivateSurfaceData::with_states(&surface, |states| {
                    states
                        .cached_state
                        .pending::<SurfaceAttributes>()
                        .frame_callbacks
                        .push((*callback).clone());
                });
            }
            wl_surface::Request::SetOpaqueRegion { region } => {
                let attributes = region.map(|r| {
                    let attributes_mutex = r.as_ref().user_data().get::<Mutex<RegionAttributes>>().unwrap();
                    attributes_mutex.lock().unwrap().clone()
                });
                PrivateSurfaceData::with_states(&surface, |states| {
                    states.cached_state.pending::<SurfaceAttributes>().opaque_region = attributes;
                });
            }
            wl_surface::Request::SetInputRegion { region } => {
                let attributes = region.map(|r| {
                    let attributes_mutex = r.as_ref().user_data().get::<Mutex<RegionAttributes>>().unwrap();
                    attributes_mutex.lock().unwrap().clone()
                });
                PrivateSurfaceData::with_states(&surface, |states| {
                    states.cached_state.pending::<SurfaceAttributes>().input_region = attributes;
                });
            }
            wl_surface::Request::Commit => {
                let mut user_impl = self.implem.borrow_mut();
                PrivateSurfaceData::invoke_commit_hooks(&surface);
                if !surface.as_ref().is_alive() {
                    // the client was killed by a hook, abort
                    return;
                }
                PrivateSurfaceData::commit(&surface);
                trace!(self.log, "Calling user implementation for wl_surface.commit");
                (&mut *user_impl)(surface, ddata);
            }
            wl_surface::Request::SetBufferTransform { transform } => {
                PrivateSurfaceData::with_states(&surface, |states| {
                    states
                        .cached_state
                        .pending::<SurfaceAttributes>()
                        .buffer_transform = transform;
                });
            }
            wl_surface::Request::SetBufferScale { scale } => {
                PrivateSurfaceData::with_states(&surface, |states| {
                    states.cached_state.pending::<SurfaceAttributes>().buffer_scale = scale;
                });
            }
            wl_surface::Request::DamageBuffer { x, y, width, height } => {
                PrivateSurfaceData::with_states(&surface, |states| {
                    states
                        .cached_state
                        .pending::<SurfaceAttributes>()
                        .damage
                        .push(Damage::Buffer(Rectangle::from_loc_and_size(
                            (x, y),
                            (width, height),
                        )))
                });
            }
            wl_surface::Request::Destroy => {
                // All is already handled by our destructor
            }
            _ => unreachable!(),
        }
    }
}

impl Cacheable for SurfaceAttributes {
    fn commit(&mut self) -> Self {
        SurfaceAttributes {
            buffer: self.buffer.take(),
            buffer_scale: self.buffer_scale,
            buffer_transform: self.buffer_transform,
            damage: std::mem::take(&mut self.damage),
            opaque_region: self.opaque_region.clone(),
            input_region: self.input_region.clone(),
            frame_callbacks: std::mem::take(&mut self.frame_callbacks),
        }
    }
    fn merge_into(self, into: &mut Self) {
        if self.buffer.is_some() {
            if let Some(BufferAssignment::Removed) = &self.buffer {
                into.damage.clear();
            }
            if let Some(BufferAssignment::NewBuffer { buffer, .. }) =
                std::mem::replace(&mut into.buffer, self.buffer)
            {
                let new_buffer = into.buffer.as_ref().and_then(|b| match b {
                    BufferAssignment::Removed => None,
                    BufferAssignment::NewBuffer { buffer, .. } => Some(buffer),
                });

                if Some(&buffer) != new_buffer {
                    buffer.release();
                }
            }
        }
        into.buffer_scale = self.buffer_scale;
        into.buffer_transform = self.buffer_transform;
        into.damage.extend(self.damage);
        into.opaque_region = self.opaque_region;
        into.input_region = self.input_region;
        into.frame_callbacks.extend(self.frame_callbacks);
    }
}

fn implement_surface<Impl>(
    surface: Main<wl_surface::WlSurface>,
    log: ::slog::Logger,
    implem: Rc<RefCell<Impl>>,
) -> wl_surface::WlSurface
where
    Impl: for<'a> FnMut(wl_surface::WlSurface, DispatchData<'a>) + 'static,
{
    surface.quick_assign({
        let mut implem = SurfaceImplem::make(log, implem);
        move |surface, req, ddata| implem.receive_surface_request(req, surface.deref().clone(), ddata)
    });
    surface.assign_destructor(Filter::new(|surface, _, _| PrivateSurfaceData::cleanup(&surface)));
    surface
        .as_ref()
        .user_data()
        .set_threadsafe(PrivateSurfaceData::new);
    PrivateSurfaceData::init(&surface);
    surface.deref().clone()
}

/*
 * wl_region
 */

fn region_implem(request: wl_region::Request, region: wl_region::WlRegion) {
    let attributes_mutex = region
        .as_ref()
        .user_data()
        .get::<Mutex<RegionAttributes>>()
        .unwrap();
    let mut guard = attributes_mutex.lock().unwrap();
    match request {
        wl_region::Request::Add { x, y, width, height } => guard.rects.push((
            RectangleKind::Add,
            Rectangle::from_loc_and_size((x, y), (width, height)),
        )),
        wl_region::Request::Subtract { x, y, width, height } => guard.rects.push((
            RectangleKind::Subtract,
            Rectangle::from_loc_and_size((x, y), (width, height)),
        )),
        wl_region::Request::Destroy => {
            // all is handled by our destructor
        }
        _ => unreachable!(),
    }
}

fn implement_region(region: Main<wl_region::WlRegion>) -> wl_region::WlRegion {
    region.quick_assign(|region, req, _| region_implem(req, region.deref().clone()));
    region
        .as_ref()
        .user_data()
        .set_threadsafe(|| Mutex::new(RegionAttributes::default()));
    region.deref().clone()
}

/*
 * wl_subcompositor
 */

pub(crate) fn implement_subcompositor(
    subcompositor: Main<wl_subcompositor::WlSubcompositor>,
) -> wl_subcompositor::WlSubcompositor {
    subcompositor.quick_assign(move |subcompositor, request, _| match request {
        wl_subcompositor::Request::GetSubsurface { id, surface, parent } => {
            if let Err(AlreadyHasRole) = PrivateSurfaceData::set_parent(&surface, &parent) {
                subcompositor.as_ref().post_error(
                    wl_subcompositor::Error::BadSurface as u32,
                    "Surface already has a role.".into(),
                );
                return;
            }
            implement_subsurface(id, surface);
        }
        wl_subcompositor::Request::Destroy => {}
        _ => unreachable!(),
    });
    subcompositor.deref().clone()
}

/*
 * wl_subsurface
 */

/// The cached state associated with a subsurface
#[derive(Debug)]
pub struct SubsurfaceCachedState {
    /// Location of the top-left corner of this subsurface
    /// relative to its parent coordinate space
    pub location: Point<i32, Logical>,
}

impl Default for SubsurfaceCachedState {
    fn default() -> Self {
        SubsurfaceCachedState {
            location: (0, 0).into(),
        }
    }
}

impl Cacheable for SubsurfaceCachedState {
    fn commit(&mut self) -> Self {
        SubsurfaceCachedState {
            location: self.location,
        }
    }

    fn merge_into(self, into: &mut Self) {
        into.location = self.location;
    }
}

pub(crate) struct SubsurfaceState {
    pub(crate) sync: AtomicBool,
}

impl SubsurfaceState {
    fn new() -> SubsurfaceState {
        SubsurfaceState {
            sync: AtomicBool::new(true),
        }
    }
}

/// Check if a (sub)surface is effectively sync
pub fn is_effectively_sync(surface: &wl_surface::WlSurface) -> bool {
    let is_direct_sync = PrivateSurfaceData::with_states(surface, |state| {
        state
            .data_map
            .get::<SubsurfaceState>()
            .map(|s| s.sync.load(Ordering::Acquire))
            .unwrap_or(false)
    });
    if is_direct_sync {
        return true;
    }
    if let Some(parent) = PrivateSurfaceData::get_parent(surface) {
        is_effectively_sync(&parent)
    } else {
        false
    }
}

fn implement_subsurface(
    subsurface: Main<wl_subsurface::WlSubsurface>,
    surface: wl_surface::WlSurface,
) -> wl_subsurface::WlSubsurface {
    let data_surface = surface.clone();
    subsurface.quick_assign(move |subsurface, request, _| {
        match request {
            wl_subsurface::Request::SetPosition { x, y } => {
                PrivateSurfaceData::with_states(&surface, |state| {
                    state.cached_state.pending::<SubsurfaceCachedState>().location = (x, y).into();
                })
            }
            wl_subsurface::Request::PlaceAbove { sibling } => {
                let surface = subsurface
                    .as_ref()
                    .user_data()
                    .get::<wl_surface::WlSurface>()
                    .unwrap();
                if let Err(()) = PrivateSurfaceData::reorder(surface, Location::After, &sibling) {
                    subsurface.as_ref().post_error(
                        wl_subsurface::Error::BadSurface as u32,
                        "Provided surface is not a sibling or parent.".into(),
                    )
                }
            }
            wl_subsurface::Request::PlaceBelow { sibling } => {
                let surface = subsurface
                    .as_ref()
                    .user_data()
                    .get::<wl_surface::WlSurface>()
                    .unwrap();
                if let Err(()) = PrivateSurfaceData::reorder(surface, Location::Before, &sibling) {
                    subsurface.as_ref().post_error(
                        wl_subsurface::Error::BadSurface as u32,
                        "Provided surface is not a sibling or parent.".into(),
                    )
                }
            }
            wl_subsurface::Request::SetSync => PrivateSurfaceData::with_states(&surface, |state| {
                state
                    .data_map
                    .get::<SubsurfaceState>()
                    .unwrap()
                    .sync
                    .store(true, Ordering::Release);
            }),
            wl_subsurface::Request::SetDesync => PrivateSurfaceData::with_states(&surface, |state| {
                state
                    .data_map
                    .get::<SubsurfaceState>()
                    .unwrap()
                    .sync
                    .store(false, Ordering::Release);
            }),
            wl_subsurface::Request::Destroy => {
                // Our destructor already handles it
            }
            _ => unreachable!(),
        }
    });
    super::with_states(&data_surface, |states| {
        states.data_map.insert_if_missing_threadsafe(SubsurfaceState::new)
    })
    .unwrap();
    subsurface.assign_destructor(Filter::new(|subsurface, _, _| destroy_subsurface(&subsurface)));
    subsurface
        .as_ref()
        .user_data()
        .set_threadsafe(move || data_surface);
    subsurface.deref().clone()
}

fn destroy_subsurface(subsurface: &wl_subsurface::WlSubsurface) {
    let surface = subsurface
        .as_ref()
        .user_data()
        .get::<wl_surface::WlSurface>()
        .unwrap();
    if surface.as_ref().is_alive() {
        PrivateSurfaceData::unset_parent(surface);
    }
}
<|endoftext|>