<commit_before>//! Wayland scanner crate
//!
//!
//! This crate is a rust equivalent of the wayland-scanner tool from the
//! official wayland C library.
//!
//! You can use in your build script to generate the rust code for any
//! wayland protocol file, to use alongside the `wayland_client` and
//! `wayland_server` crate to build your applications.
//!
//! TODO: How to use this crate?
extern crate xml;

use std::fs::{File, OpenOptions};
use std::path::Path;

mod util;
mod parse;
mod protocol;
mod side;
mod interface_gen;
mod code_gen;

pub use side::Side;

fn load_xml<P: AsRef<Path>>(prot: P) -> protocol::Protocol {
    let pfile = File::open(prot).unwrap();
    parse::parse_stream(pfile)
}

/// Generate the interfaces for a protocol
///
/// See this crate toplevel documentation for details.
///
/// Args:
///
/// - `protocol`: a path to the XML file describing the protocol, absolute or relative to
///   the build script using this function.
/// - `target`: the path of the file to store this interfaces in.
pub fn generate_interfaces<P1: AsRef<Path>, P2: AsRef<Path>>(protocol: P1, target: P2) {
    let protocol = load_xml(protocol);
    let mut out = OpenOptions::new().write(true).truncate(true).create(true).open(target).unwrap();
    interface_gen::generate_interfaces(protocol, &mut out);
}

/// Generate the code for a protocol
///
/// See this crate toplevel documentation for details.
///
/// Args:
///
/// - `protocol`: a path to the XML file describing the protocol, absolute or relative to
///   the build script using this function.
/// - `target`: the path of the file to store the code in.
/// - `side`: the side (client or server) to generate code for.
pub fn generate_code<P1: AsRef<Path>, P2: AsRef<Path>>(prot: P1, target: P2, side: Side) {
    let protocol = load_xml(prot);
    let mut out = OpenOptions::new().write(true).truncate(true).create(true).open(target).unwrap();
    code_gen::write_protocol(protocol, &mut out, side).unwrap()
}
<commit_msg>scanner: howto docs<commit_after>//! Wayland scanner crate
//!
//!
//! This crate is a rust equivalent of the wayland-scanner tool from the
//! official wayland C library.
//!
//! You can use in your build script to generate the rust code for any
//! wayland protocol file, to use alongside the `wayland_client` and
//! `wayland_server` crate to build your applications.
//!
//! ## How to use this crate
//!
//! This crate is to be used in a build script. It provides you two
//! functions, `generate_code` and `generate_interfaces`. They'll
//! allow you to generate the code to use with the `wayland_client` or
//! `wayland_server` crates for any XML wayland protocol file (NB: you don't
//! need to do it for the core protocol, which is already included in both crates).
//!
//! First, have the XML files you want to use in your project, somewhere the build script
//! will be able to read them.
//!
//! Then, you'll need to invoke both `generate_interfaces` *and* `generate_code` for
//! each of these files.
//!
//! A sample build script:
//!
//! ```no_run
//! extern crate wayland_scanner;
//!
//! use std::env::var;
//! use std::path::Path;
//!
//! use wayland_scanner::{Side, generate_code, generate_interfaces};
//!
//! fn main() {
//!     // Location of the xml file, relative to the `Cargo.toml`
//!     let protocol_file = "./my_protocol.xml";
//!
//!     // Target directory for the generate files
//!     let out_dir_str = var("OUT_DIR").unwrap();
//!     let out_dir = Path::new(&out_dir_str);
//!
//!     generate_code(
//!         protocol_file,
//!         out_dir.join("my_protocol_api.rs"),
//!         Side::Client, // Replace by `Side::Server` for server-side code
//!     );
//!
//!     // interfaces are the same for client and server
//!     generate_interfaces(
//!         protocol_file,
//!         out_dir.join("my_protocol_interfaces.rs")
//!     );
//! }
//! ```
//!
//! The above example will output two `.rs` files in the `OUT_DIR` defined by
//! cargo. Then, you'll need to include these two generated files (using the
//! macro of the same name) to make this code available in your crate.
//!
//! ```ignore
//! // The generated code will import stuff from wayland_sys
//! extern crate wayland_sys;
//! extern crate wayland_client;
//!
//! // Re-export only the actual code, and then only use this re-export
//! // The `generated` module below is just some boilerplate to properly isolate stuff
//! // and avoid exposing internal details.
//! //
//! // You can use all the types from my_procol as if they went from `wayland_client::protocol`.
//! pub use generated::client as my_protocol;
//!
//! mod generated {
//!     // The generated code tends to trigger a lot of warnings
//!     // so we isole it into a very permissive module
//!     #![allow(dead_code,non_camel_case_types,unused_unsafe,unused_variables)]
//!     #![allow(non_upper_case_globals,non_snake_case,unused_imports)]
//!
//!     pub mod interfaces {
//!         // include the interfaces, they just need to be accessible to the generated code
//!         // so this module is `pub` so that it can be imported by the other one.
//!         include!(concat!(env!("OUT_DIR"), "/my_protocol_interfaces.rs"));
//!     }
//!
//!     pub mod client {
//!         // These import are mandatory, and need to by `pub`, because
//!         // submodules in the generated code will try to import them.
//!         // Hopefully someday pub(restricted) and friends will
//!         // allow for a cleaner way to do that
//!         #[doc(hidden)] pub use wayland_client::{Proxy, Handler, EventQueueHandle};
//!         // Replace the above line with this for server-side:
//!         // #[doc(hidden)] pub use wayland_server::{Resource, Handler, EventLoopHandle};
//!         #[doc(hidden)] pub use super::interfaces;
//!         // If you protocol interacts with objects from other protocols, you'll need to import
//!         // their modules, like so:
//!         #[doc(hidden)] pub use wayland_client::protocol::{wl_surface, wl_region};
//!         include!(concat!(env!("OUT_DIR"), "/my_protocol_code.rs"));
//!     }
//! }
//! ```
extern crate xml;

use std::fs::{File, OpenOptions};
use std::path::Path;

mod util;
mod parse;
mod protocol;
mod side;
mod interface_gen;
mod code_gen;

pub use side::Side;

fn load_xml<P: AsRef<Path>>(prot: P) -> protocol::Protocol {
    let pfile = File::open(prot).unwrap();
    parse::parse_stream(pfile)
}

/// Generate the interfaces for a protocol
///
/// See this crate toplevel documentation for details.
///
/// Args:
///
/// - `protocol`: a path to the XML file describing the protocol, absolute or relative to
///   the build script using this function.
/// - `target`: the path of the file to store this interfaces in.
pub fn generate_interfaces<P1: AsRef<Path>, P2: AsRef<Path>>(protocol: P1, target: P2) {
    let protocol = load_xml(protocol);
    let mut out = OpenOptions::new().write(true).truncate(true).create(true).open(target).unwrap();
    interface_gen::generate_interfaces(protocol, &mut out);
}

/// Generate the code for a protocol
///
/// See this crate toplevel documentation for details.
///
/// Args:
///
/// - `protocol`: a path to the XML file describing the protocol, absolute or relative to
///   the build script using this function.
/// - `target`: the path of the file to store the code in.
/// - `side`: the side (client or server) to generate code for.
pub fn generate_code<P1: AsRef<Path>, P2: AsRef<Path>>(prot: P1, target: P2, side: Side) {
    let protocol = load_xml(prot);
    let mut out = OpenOptions::new().write(true).truncate(true).create(true).open(target).unwrap();
    code_gen::write_protocol(protocol, &mut out, side).unwrap()
}
<|endoftext|>


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

//! Allows for the root trust_anchor to either be added to or replaced for dns_sec validation.

use std::default::Default;

#[cfg(feature = "openssl")]
use openssl::crypto::rsa::RSA;

#[cfg(feature = "openssl")]
use ::rr::dnssec::Algorithm;

#[cfg(feature = "openssl")]
const ROOT_ANCHOR: &'static str = include_str!("Kjqmt7v.pem");

// TODO: these should also store some information, or more specifically, metadata from the signed
//  public certificate.
pub struct TrustAnchor {
  pkeys: Vec<Vec<u8>>
}

impl Default for TrustAnchor {
  #[cfg(feature = "openssl")]
  fn default() -> TrustAnchor {
    let rsa = RSA::public_key_from_pem(ROOT_ANCHOR.as_bytes()).expect("Error parsing Kjqmt7v.pem");
    assert_eq!(rsa.size().unwrap(), 256);

    let alg = Algorithm::RSASHA256;

    TrustAnchor{ pkeys: vec![alg.public_key_to_vec(&rsa)] }
  }

  #[cfg(not(feature = "openssl"))]
  fn default() -> TrustAnchor {
    TrustAnchor{ pkeys: vec![] }
  }
}

impl TrustAnchor {
  pub fn new() -> TrustAnchor {
    TrustAnchor { pkeys: vec![] }
  }

  pub fn contains(&self, other_key: &[u8]) -> bool {
    self.pkeys.iter().any(|k|other_key == k as &[u8])
  }

  /// inserts the trust_anchor to the trusted chain
  pub fn insert_trust_anchor(&mut self, public_key: Vec<u8>) {
    if !self.contains(&public_key) {
      self.pkeys.push(public_key)
    }
  }
}
<commit_msg>add byte format test for trust_keys<commit_after>/*
 * Copyright (C) 2015 Benjamin Fry <benjaminfry@me.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//! Allows for the root trust_anchor to either be added to or replaced for dns_sec validation.

use std::default::Default;

#[cfg(feature = "openssl")]
use openssl::crypto::rsa::RSA;

#[cfg(feature = "openssl")]
use ::rr::dnssec::Algorithm;

#[cfg(feature = "openssl")]
const ROOT_ANCHOR: &'static str = include_str!("Kjqmt7v.pem");

// TODO: these should also store some information, or more specifically, metadata from the signed
//  public certificate.
pub struct TrustAnchor {
  pkeys: Vec<Vec<u8>>
}

impl Default for TrustAnchor {
  #[cfg(feature = "openssl")]
  fn default() -> TrustAnchor {
    let rsa = RSA::public_key_from_pem(ROOT_ANCHOR.as_bytes()).expect("Error parsing Kjqmt7v.pem");
    assert_eq!(rsa.size().unwrap(), 256);

    let alg = Algorithm::RSASHA256;

    TrustAnchor{ pkeys: vec![alg.public_key_to_vec(&rsa)] }
  }

  #[cfg(not(feature = "openssl"))]
  fn default() -> TrustAnchor {
    TrustAnchor{ pkeys: vec![] }
  }
}

impl TrustAnchor {
  pub fn new() -> TrustAnchor {
    TrustAnchor { pkeys: vec![] }
  }

  pub fn contains(&self, other_key: &[u8]) -> bool {
    self.pkeys.iter().any(|k|other_key == k as &[u8])
  }

  /// inserts the trust_anchor to the trusted chain
  pub fn insert_trust_anchor(&mut self, public_key: Vec<u8>) {
    if !self.contains(&public_key) {
      self.pkeys.push(public_key)
    }
  }

  pub fn get(&self, idx: usize) -> &[u8] {
    &self.pkeys[idx]
  }
}

#[test]
fn dump_keys() {
  let trust = TrustAnchor::default();
  let test_kjqmt7v: Vec<u8> = vec![3, 1, 0, 1, 168, 0, 32, 169, 85, 102, 186, 66, 232, 134, 187,
                                   128, 76, 218, 132, 228, 126, 245, 109, 189, 122, 236, 97, 38,
                                   21, 85, 44, 236, 144, 109, 33, 22, 208, 239, 32, 112, 40, 197,
                                   21, 84, 20, 77, 254, 175, 231, 199, 203, 143, 0, 93, 209, 130,
                                   52, 19, 58, 192, 113, 10, 129, 24, 44, 225, 253, 20, 173, 34,
                                   131, 188, 131, 67, 95, 157, 242, 246, 49, 50, 81, 147, 26, 23,
                                   109, 240, 218, 81, 229, 79, 66, 230, 4, 134, 13, 251, 53, 149,
                                   128, 37, 15, 85, 156, 197, 67, 196, 255, 213, 28, 190, 61, 232,
                                   207, 208, 103, 25, 35, 127, 159, 196, 126, 231, 41, 218, 6, 131,
                                   95, 164, 82, 232, 37, 233, 161, 142, 188, 46, 203, 207, 86, 52,
                                   116, 101, 44, 51, 207, 86, 169, 3, 59, 205, 245, 217, 115, 18,
                                   23, 151, 236, 128, 137, 4, 27, 110, 3, 161, 183, 45, 10, 115,
                                   91, 152, 78, 3, 104, 115, 9, 51, 35, 36, 242, 124, 45, 186,
                                   133, 233, 219, 21, 232, 58, 1, 67, 56, 46, 151, 75, 6, 33,
                                   193, 142, 98, 94, 206, 201, 7, 87, 125, 158, 123, 173, 233, 82,
                                   65, 168, 30, 187, 232, 169, 1, 212, 211, 39, 110, 64, 177, 20,
                                   192, 162, 230, 252, 56, 209, 156, 46, 106, 171, 2, 100, 75, 40,
                                   19, 245, 117, 252, 33, 96, 30, 13, 238, 73, 205, 158, 233,
                                   106, 67, 16, 62, 82, 77, 98, 135, 61];

  assert_eq!(trust.get(0), &test_kjqmt7v as &[u8]);
}
<|endoftext|>


<commit_before>// Copyright 2022 TiKV Project Authors. Licensed under Apache-2.0.

use std::sync::Arc;

use api_version::{ApiV2, KeyMode, KvFormat};
use engine_traits::KvEngine;
use kvproto::raft_cmdpb::{CmdType, Request as RaftRequest};
use raft::StateRole;
use raftstore::{
    coprocessor,
    coprocessor::{
        BoxQueryObserver, BoxRoleObserver, Coprocessor, CoprocessorHost, ObserverContext,
        QueryObserver, RoleChange, RoleObserver,
    },
};

use crate::CausalTsProvider;

/// CausalObserver appends timestamp for RawKV V2 data,
/// and invoke causal_ts_provider.flush() on specified event, e.g. leader transfer, snapshot apply.
/// Should be used ONLY when API v2 is enabled.
pub struct CausalObserver<Ts: CausalTsProvider> {
    causal_ts_provider: Arc<Ts>,
}

impl<Ts: CausalTsProvider> Clone for CausalObserver<Ts> {
    fn clone(&self) -> Self {
        Self {
            causal_ts_provider: self.causal_ts_provider.clone(),
        }
    }
}

// Causal observer's priority should be higher than all other observers, to avoid being bypassed.
const CAUSAL_OBSERVER_PRIORITY: u32 = 0;

impl<Ts: CausalTsProvider + 'static> CausalObserver<Ts> {
    pub fn new(causal_ts_provider: Arc<Ts>) -> Self {
        Self { causal_ts_provider }
    }

    pub fn register_to<E: KvEngine>(&self, coprocessor_host: &mut CoprocessorHost<E>) {
        coprocessor_host.registry.register_query_observer(
            CAUSAL_OBSERVER_PRIORITY,
            BoxQueryObserver::new(self.clone()),
        );
        coprocessor_host
            .registry
            .register_role_observer(CAUSAL_OBSERVER_PRIORITY, BoxRoleObserver::new(self.clone()));
    }
}

impl<Ts: CausalTsProvider> Coprocessor for CausalObserver<Ts> {}

impl<Ts: CausalTsProvider> QueryObserver for CausalObserver<Ts> {
    fn pre_propose_query(
        &self,
        _: &mut ObserverContext<'_>,
        requests: &mut Vec<RaftRequest>,
    ) -> coprocessor::Result<()> {
        let mut ts = None;

        for req in requests.iter_mut().filter(|r| {
            r.get_cmd_type() == CmdType::Put
                && ApiV2::parse_key_mode(r.get_put().get_key()) == KeyMode::Raw
        }) {
            if ts.is_none() {
                ts = Some(self.causal_ts_provider.get_ts().map_err(|err| {
                    coprocessor::Error::Other(box_err!("Get causal timestamp error: {:?}", err))
                })?);
            }

            ApiV2::append_ts_on_encoded_bytes(req.mut_put().mut_key(), ts.unwrap());
        }
        Ok(())
    }
}

impl<Ts: CausalTsProvider> RoleObserver for CausalObserver<Ts> {
    /// Observe becoming leader, to flush CausalTsProvider.
    fn on_role_change(&self, ctx: &mut ObserverContext<'_>, role_change: &RoleChange) {
        if role_change.state == StateRole::Leader {
            let region_id = ctx.region().get_id();
            if let Err(err) = self.causal_ts_provider.flush() {
                warn!("CausalObserver::on_role_change, flush timestamp error"; "region" => region_id, "error" => ?err);
            } else {
                debug!("CausalObserver::on_role_change, flush timestamp succeed"; "region" => region_id);
            }
        }
    }
}

#[cfg(test)]
pub mod tests {
    use std::{mem, sync::Arc, time::Duration};

    use api_version::{ApiV2, KvFormat};
    use futures::executor::block_on;
    use kvproto::{
        metapb::Region,
        raft_cmdpb::{RaftCmdRequest, Request as RaftRequest},
    };
    use test_raftstore::TestPdClient;
    use txn_types::{Key, TimeStamp};

    use super::*;
    use crate::BatchTsoProvider;

    fn init() -> CausalObserver<BatchTsoProvider<TestPdClient>> {
        let pd_cli = Arc::new(TestPdClient::new(0, true));
        pd_cli.set_tso(100.into());
        let causal_ts_provider =
            Arc::new(block_on(BatchTsoProvider::new_opt(pd_cli, Duration::ZERO, 100)).unwrap());
        CausalObserver::new(causal_ts_provider)
    }

    #[test]
    fn test_causal_observer() {
        let testcases: Vec<&[&[u8]]> = vec![
            &[b"r\0a", b"r\0b"],
            &[b"r\0c"],
            &[b"r\0d", b"r\0e", b"r\0f"],
        ];

        let ob = init();
        let mut region = Region::default();
        region.set_id(1);
        let mut ctx = ObserverContext::new(&region);

        for (i, keys) in testcases.into_iter().enumerate() {
            let mut cmd_req = RaftCmdRequest::default();

            for key in keys {
                let key = ApiV2::encode_raw_key(key, None);
                let value = b"value".to_vec();
                let mut req = RaftRequest::default();
                req.set_cmd_type(CmdType::Put);
                req.mut_put().set_key(key.into_encoded());
                req.mut_put().set_value(value);

                cmd_req.mut_requests().push(req);
            }

            let query = cmd_req.mut_requests();
            let mut vec_query: Vec<RaftRequest> = mem::take(query).into();
            ob.pre_propose_query(&mut ctx, &mut vec_query).unwrap();
            *query = vec_query.into();

            for req in cmd_req.get_requests() {
                let key = Key::from_encoded_slice(req.get_put().get_key());
                let (_, ts) = ApiV2::decode_raw_key_owned(key, true).unwrap();
                assert_eq!(ts, Some(TimeStamp::from(i as u64 + 101)));
            }
        }
    }
}
<commit_msg>causal_ts: fix issue #12498 (#12573)<commit_after>// Copyright 2022 TiKV Project Authors. Licensed under Apache-2.0.

use std::sync::Arc;

use api_version::{ApiV2, KeyMode, KvFormat};
use engine_traits::KvEngine;
use kvproto::raft_cmdpb::{CmdType, Request as RaftRequest};
use raft::StateRole;
use raftstore::{
    coprocessor,
    coprocessor::{
        BoxQueryObserver, BoxRoleObserver, Coprocessor, CoprocessorHost, ObserverContext,
        QueryObserver, RoleChange, RoleObserver,
    },
};

use crate::CausalTsProvider;

/// CausalObserver appends timestamp for RawKV V2 data,
/// and invoke causal_ts_provider.flush() on specified event, e.g. leader transfer, snapshot apply.
/// Should be used ONLY when API v2 is enabled.
pub struct CausalObserver<Ts: CausalTsProvider> {
    causal_ts_provider: Arc<Ts>,
}

impl<Ts: CausalTsProvider> Clone for CausalObserver<Ts> {
    fn clone(&self) -> Self {
        Self {
            causal_ts_provider: self.causal_ts_provider.clone(),
        }
    }
}

// Causal observer's priority should be higher than all other observers, to avoid being bypassed.
const CAUSAL_OBSERVER_PRIORITY: u32 = 0;

impl<Ts: CausalTsProvider + 'static> CausalObserver<Ts> {
    pub fn new(causal_ts_provider: Arc<Ts>) -> Self {
        Self { causal_ts_provider }
    }

    pub fn register_to<E: KvEngine>(&self, coprocessor_host: &mut CoprocessorHost<E>) {
        coprocessor_host.registry.register_query_observer(
            CAUSAL_OBSERVER_PRIORITY,
            BoxQueryObserver::new(self.clone()),
        );
        coprocessor_host
            .registry
            .register_role_observer(CAUSAL_OBSERVER_PRIORITY, BoxRoleObserver::new(self.clone()));
    }
}

impl<Ts: CausalTsProvider> Coprocessor for CausalObserver<Ts> {}

impl<Ts: CausalTsProvider> QueryObserver for CausalObserver<Ts> {
    fn pre_propose_query(
        &self,
        _: &mut ObserverContext<'_>,
        requests: &mut Vec<RaftRequest>,
    ) -> coprocessor::Result<()> {
        let mut ts = None;

        for req in requests.iter_mut().filter(|r| {
            r.get_cmd_type() == CmdType::Put
                && ApiV2::parse_key_mode(r.get_put().get_key()) == KeyMode::Raw
        }) {
            if ts.is_none() {
                ts = Some(self.causal_ts_provider.get_ts().map_err(|err| {
                    coprocessor::Error::Other(box_err!("Get causal timestamp error: {:?}", err))
                })?);
            }

            ApiV2::append_ts_on_encoded_bytes(req.mut_put().mut_key(), ts.unwrap());
        }
        Ok(())
    }
}

impl<Ts: CausalTsProvider> RoleObserver for CausalObserver<Ts> {
    /// Observe becoming leader, to flush CausalTsProvider.
    fn on_role_change(&self, ctx: &mut ObserverContext<'_>, role_change: &RoleChange) {
        // In scenario of frequent leader transfer, the observing of change from
        // follower to leader by `on_role_change` would be later than the real role
        // change in raft state and adjacent write commands.
        // This would lead to the late of flush, and violate causality. See issue #12498.
        // So we observe role change to Candidate to fix this issue.
        // Also note that when there is only one peer, it would become leader directly.
        if role_change.state == StateRole::Candidate
            || (ctx.region().peers.len() == 1 && role_change.state == StateRole::Leader)
        {
            let region_id = ctx.region().get_id();
            if let Err(err) = self.causal_ts_provider.flush() {
                warn!("CausalObserver::on_role_change, flush timestamp error"; "region" => region_id, "error" => ?err);
            } else {
                debug!("CausalObserver::on_role_change, flush timestamp succeed"; "region" => region_id);
            }
        }
    }
}

#[cfg(test)]
pub mod tests {
    use std::{mem, sync::Arc, time::Duration};

    use api_version::{ApiV2, KvFormat};
    use futures::executor::block_on;
    use kvproto::{
        metapb::Region,
        raft_cmdpb::{RaftCmdRequest, Request as RaftRequest},
    };
    use test_raftstore::TestPdClient;
    use txn_types::{Key, TimeStamp};

    use super::*;
    use crate::BatchTsoProvider;

    fn init() -> CausalObserver<BatchTsoProvider<TestPdClient>> {
        let pd_cli = Arc::new(TestPdClient::new(0, true));
        pd_cli.set_tso(100.into());
        let causal_ts_provider =
            Arc::new(block_on(BatchTsoProvider::new_opt(pd_cli, Duration::ZERO, 100)).unwrap());
        CausalObserver::new(causal_ts_provider)
    }

    #[test]
    fn test_causal_observer() {
        let testcases: Vec<&[&[u8]]> = vec![
            &[b"r\0a", b"r\0b"],
            &[b"r\0c"],
            &[b"r\0d", b"r\0e", b"r\0f"],
        ];

        let ob = init();
        let mut region = Region::default();
        region.set_id(1);
        let mut ctx = ObserverContext::new(&region);

        for (i, keys) in testcases.into_iter().enumerate() {
            let mut cmd_req = RaftCmdRequest::default();

            for key in keys {
                let key = ApiV2::encode_raw_key(key, None);
                let value = b"value".to_vec();
                let mut req = RaftRequest::default();
                req.set_cmd_type(CmdType::Put);
                req.mut_put().set_key(key.into_encoded());
                req.mut_put().set_value(value);

                cmd_req.mut_requests().push(req);
            }

            let query = cmd_req.mut_requests();
            let mut vec_query: Vec<RaftRequest> = mem::take(query).into();
            ob.pre_propose_query(&mut ctx, &mut vec_query).unwrap();
            *query = vec_query.into();

            for req in cmd_req.get_requests() {
                let key = Key::from_encoded_slice(req.get_put().get_key());
                let (_, ts) = ApiV2::decode_raw_key_owned(key, true).unwrap();
                assert_eq!(ts, Some(TimeStamp::from(i as u64 + 101)));
            }
        }
    }
}
<|endoftext|>


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

use dom::audionode::MAX_CHANNEL_COUNT;
use dom::bindings::cell::DomRefCell;
use dom::bindings::codegen::Bindings::AudioBufferBinding::{self, AudioBufferMethods, AudioBufferOptions};
use dom::bindings::error::{Error, Fallible};
use dom::bindings::num::Finite;
use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::bindings::root::DomRoot;
use dom::window::Window;
use dom_struct::dom_struct;
use js::jsapi::{Heap, JSContext, JSObject, JS_StealArrayBufferContents};
use js::rust::CustomAutoRooterGuard;
use js::typedarray::{CreateWith, Float32Array};
use servo_media::audio::buffer_source_node::AudioBuffer as ServoMediaAudioBuffer;
use std::cmp::min;
use std::ptr::{self, NonNull};

type JSAudioChannel = Heap<*mut JSObject>;

#[dom_struct]
pub struct AudioBuffer {
    reflector_: Reflector,
    js_channels: DomRefCell<Vec<JSAudioChannel>>,
    #[ignore_malloc_size_of = "servo_media"]
    shared_channels: DomRefCell<ServoMediaAudioBuffer>,
    sample_rate: f32,
    length: u32,
    duration: f64,
    number_of_channels: u32,
}

impl AudioBuffer {
    #[allow(unrooted_must_root)]
    #[allow(unsafe_code)]
    pub fn new_inherited(cx: *mut JSContext,
                         number_of_channels: u32,
                         length: u32,
                         sample_rate: f32,
                         initial_data: Option<&[f32]>) -> AudioBuffer {
        let initial_data = match initial_data {
            Some(initial_data) => {
                let mut data = vec![];
                data.extend_from_slice(initial_data);
                data
            },
            None => vec![0.; (length * number_of_channels) as usize]
        };
        let mut js_channels: Vec<JSAudioChannel> = Vec::with_capacity(number_of_channels as usize);
        for channel in 0..number_of_channels {
            rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
            let offset = (channel * length) as usize;
            let _ = unsafe {
                Float32Array::create(
                    cx,
                    CreateWith::Slice(&initial_data.as_slice()[offset..offset + (length as usize)]),
                    array.handle_mut())
            };
            let js_channel = Heap::default();
            js_channel.set(array.get());
            js_channels.push(js_channel);
        }
        AudioBuffer {
            reflector_: Reflector::new(),
            js_channels: DomRefCell::new(js_channels),
            shared_channels: DomRefCell::new(ServoMediaAudioBuffer::new(number_of_channels as u8, length as usize)),
            sample_rate,
            length,
            duration: length as f64 / sample_rate as f64,
            number_of_channels,
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(global: &Window,
               number_of_channels: u32,
               length: u32,
               sample_rate: f32,
               initial_data: Option<&[f32]>) -> DomRoot<AudioBuffer> {
        let buffer = AudioBuffer::new_inherited(global.get_cx(), number_of_channels, length, sample_rate, initial_data);
        reflect_dom_object(Box::new(buffer), global, AudioBufferBinding::Wrap)
    }

    pub fn Constructor(window: &Window,
                       options: &AudioBufferOptions) -> Fallible<DomRoot<AudioBuffer>> {
        if options.numberOfChannels > MAX_CHANNEL_COUNT {
            return Err(Error::NotSupported);
        }
        Ok(AudioBuffer::new(window, options.numberOfChannels, options.length, *options.sampleRate, None))
    }

    #[allow(unsafe_code)]
    fn restore_js_channel_data(&self, cx: *mut JSContext) -> bool {
        for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
            if !channel.get().is_null() {
                // Already have data in JS array.
                continue;
            }

            // Move the channel data from shared_channels to js_channels.
            rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
            let shared_channel = (*self.shared_channels.borrow_mut()).buffers.remove(i);
            if unsafe {
                Float32Array::create(cx, CreateWith::Slice(&shared_channel), array.handle_mut())
            }.is_err() {
                return false;
            }
            channel.set(array.get());
        }

        true
    }

    // https://webaudio.github.io/web-audio-api/#acquire-the-content
    #[allow(unsafe_code)]
    pub fn acquire_contents(&self) -> Option<ServoMediaAudioBuffer> {
        let cx = self.global().get_cx();
        for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
            // Step 1.
            if channel.get().is_null() {
                return None;
            }

            // Step 2.
            let channel_data = unsafe {
                typedarray!(in(cx) let array: Float32Array = channel.get());
                if let Ok(array) = array {
                    // XXX TypedArrays API does not expose a way to steal the buffer's
                    //     content.
                    let data = array.to_vec();
                    let _ = JS_StealArrayBufferContents(cx, channel.handle());
                    data
                } else {
                    return None;
                }
            };

            channel.set(ptr::null_mut());

            // Step 3.
            (*self.shared_channels.borrow_mut()).buffers[i] = channel_data;

            // Step 4 will complete turning shared_channels
            // data into js_channels ArrayBuffers in restore_js_channel_data.
        }

        self.js_channels.borrow_mut().clear();

        Some((*self.shared_channels.borrow()).clone())
    }
}

impl AudioBufferMethods for AudioBuffer {
    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-samplerate
    fn SampleRate(&self) -> Finite<f32> {
        Finite::wrap(self.sample_rate)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-length
    fn Length(&self) -> u32 {
        self.length
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-duration
    fn Duration(&self) -> Finite<f64> {
        Finite::wrap(self.duration)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-numberofchannels
    fn NumberOfChannels(&self) -> u32 {
        self.number_of_channels
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-getchanneldata
    #[allow(unsafe_code)]
    unsafe fn GetChannelData(&self, cx: *mut JSContext, channel: u32) -> Fallible<NonNull<JSObject>> {
        if channel >= self.number_of_channels {
            return Err(Error::IndexSize);
        }

        if !self.restore_js_channel_data(cx) {
            return Err(Error::JSFailed);
        }

        Ok(NonNull::new_unchecked(self.js_channels.borrow()[channel as usize].get()))
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copyfromchannel
    #[allow(unsafe_code)]
    fn CopyFromChannel(&self,
                       mut destination: CustomAutoRooterGuard<Float32Array>,
                       channel_number: u32,
                       start_in_channel: u32) -> Fallible<()> {
        if channel_number >= self.number_of_channels || start_in_channel > self.length {
            return Err(Error::IndexSize);
        }

        let bytes_to_copy = min(self.length - start_in_channel, destination.len() as u32) as usize;
        let cx = self.global().get_cx();
        let channel_number = channel_number as usize;
        let offset = start_in_channel as usize;
        let mut dest = Vec::with_capacity(destination.len());
        // let destination = unsafe { destination.as_mut_slice() };

        // We either copy form js_channels or shared_channels.

        let js_channel = self.js_channels.borrow()[channel_number].get();
        if !js_channel.is_null() {
            typedarray!(in(cx) let array: Float32Array = js_channel);
            if let Ok(array) = array {
                let data = unsafe { array.as_slice() };
                dest.extend_from_slice(&data[offset..offset + bytes_to_copy]);
                return Ok(());
            }
        }

        if let Some(shared_channel) = self.shared_channels.borrow().buffers.get(channel_number) {
            dest.extend_from_slice(&shared_channel.as_slice()[offset..offset + bytes_to_copy]);
        }

        unsafe { destination.update(&dest); }

        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copytochannel
    #[allow(unsafe_code)]
    fn CopyToChannel(&self,
                     source: CustomAutoRooterGuard<Float32Array>,
                     channel_number: u32,
                     start_in_channel: u32) -> Fallible<()> {
        if channel_number >= self.number_of_channels || start_in_channel > (source.len() as u32) {
            return Err(Error::IndexSize);
        }

        let cx = self.global().get_cx();
        if !self.restore_js_channel_data(cx) {
            return Err(Error::JSFailed);
        }

        let js_channel = self.js_channels.borrow()[channel_number as usize].get();
        if js_channel.is_null() {
            // The array buffer was detached.
            return Err(Error::IndexSize);
        }

        typedarray!(in(cx) let array: Float32Array = js_channel);
        if let Ok(mut array) = array {
            let bytes_to_copy = min(self.length - start_in_channel, source.len() as u32) as usize;
            let offset = start_in_channel as usize;
            unsafe { array.update(&source.as_slice()[offset..offset + bytes_to_copy]); }
        } else {
            return Err(Error::IndexSize);
        }

        Ok(())
    }
}
<commit_msg>Pass global to AudioBuffer::new_inherited<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::audionode::MAX_CHANNEL_COUNT;
use dom::bindings::cell::DomRefCell;
use dom::bindings::codegen::Bindings::AudioBufferBinding::{self, AudioBufferMethods, AudioBufferOptions};
use dom::bindings::error::{Error, Fallible};
use dom::bindings::num::Finite;
use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::bindings::root::DomRoot;
use dom::window::Window;
use dom_struct::dom_struct;
use js::jsapi::{Heap, JSContext, JSObject, JS_StealArrayBufferContents};
use js::rust::CustomAutoRooterGuard;
use js::typedarray::{CreateWith, Float32Array};
use servo_media::audio::buffer_source_node::AudioBuffer as ServoMediaAudioBuffer;
use std::cmp::min;
use std::ptr::{self, NonNull};

type JSAudioChannel = Heap<*mut JSObject>;

#[dom_struct]
pub struct AudioBuffer {
    reflector_: Reflector,
    js_channels: DomRefCell<Vec<JSAudioChannel>>,
    #[ignore_malloc_size_of = "servo_media"]
    shared_channels: DomRefCell<ServoMediaAudioBuffer>,
    sample_rate: f32,
    length: u32,
    duration: f64,
    number_of_channels: u32,
}

impl AudioBuffer {
    #[allow(unrooted_must_root)]
    #[allow(unsafe_code)]
    pub fn new_inherited(global: &Window,
                         number_of_channels: u32,
                         length: u32,
                         sample_rate: f32,
                         initial_data: Option<&[f32]>) -> AudioBuffer {
        let initial_data = match initial_data {
            Some(initial_data) => {
                let mut data = vec![];
                data.extend_from_slice(initial_data);
                data
            },
            None => vec![0.; (length * number_of_channels) as usize]
        };
        let cx = global.get_cx();
        let mut js_channels: Vec<JSAudioChannel> = Vec::with_capacity(number_of_channels as usize);
        for channel in 0..number_of_channels {
            rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
            let offset = (channel * length) as usize;
            let _ = unsafe {
                Float32Array::create(
                    cx,
                    CreateWith::Slice(&initial_data.as_slice()[offset..offset + (length as usize)]),
                    array.handle_mut())
            };
            let js_channel = Heap::default();
            js_channel.set(array.get());
            js_channels.push(js_channel);
        }
        AudioBuffer {
            reflector_: Reflector::new(),
            js_channels: DomRefCell::new(js_channels),
            shared_channels: DomRefCell::new(ServoMediaAudioBuffer::new(number_of_channels as u8, length as usize)),
            sample_rate,
            length,
            duration: length as f64 / sample_rate as f64,
            number_of_channels,
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(global: &Window,
               number_of_channels: u32,
               length: u32,
               sample_rate: f32,
               initial_data: Option<&[f32]>) -> DomRoot<AudioBuffer> {
        let buffer = AudioBuffer::new_inherited(global, number_of_channels, length, sample_rate, initial_data);
        reflect_dom_object(Box::new(buffer), global, AudioBufferBinding::Wrap)
    }

    pub fn Constructor(window: &Window,
                       options: &AudioBufferOptions) -> Fallible<DomRoot<AudioBuffer>> {
        if options.numberOfChannels > MAX_CHANNEL_COUNT {
            return Err(Error::NotSupported);
        }
        Ok(AudioBuffer::new(window, options.numberOfChannels, options.length, *options.sampleRate, None))
    }

    #[allow(unsafe_code)]
    fn restore_js_channel_data(&self, cx: *mut JSContext) -> bool {
        for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
            if !channel.get().is_null() {
                // Already have data in JS array.
                continue;
            }

            // Move the channel data from shared_channels to js_channels.
            rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
            let shared_channel = (*self.shared_channels.borrow_mut()).buffers.remove(i);
            if unsafe {
                Float32Array::create(cx, CreateWith::Slice(&shared_channel), array.handle_mut())
            }.is_err() {
                return false;
            }
            channel.set(array.get());
        }

        true
    }

    // https://webaudio.github.io/web-audio-api/#acquire-the-content
    #[allow(unsafe_code)]
    pub fn acquire_contents(&self) -> Option<ServoMediaAudioBuffer> {
        let cx = self.global().get_cx();
        for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
            // Step 1.
            if channel.get().is_null() {
                return None;
            }

            // Step 2.
            let channel_data = unsafe {
                typedarray!(in(cx) let array: Float32Array = channel.get());
                if let Ok(array) = array {
                    // XXX TypedArrays API does not expose a way to steal the buffer's
                    //     content.
                    let data = array.to_vec();
                    let _ = JS_StealArrayBufferContents(cx, channel.handle());
                    data
                } else {
                    return None;
                }
            };

            channel.set(ptr::null_mut());

            // Step 3.
            (*self.shared_channels.borrow_mut()).buffers[i] = channel_data;

            // Step 4 will complete turning shared_channels
            // data into js_channels ArrayBuffers in restore_js_channel_data.
        }

        self.js_channels.borrow_mut().clear();

        Some((*self.shared_channels.borrow()).clone())
    }
}

impl AudioBufferMethods for AudioBuffer {
    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-samplerate
    fn SampleRate(&self) -> Finite<f32> {
        Finite::wrap(self.sample_rate)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-length
    fn Length(&self) -> u32 {
        self.length
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-duration
    fn Duration(&self) -> Finite<f64> {
        Finite::wrap(self.duration)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-numberofchannels
    fn NumberOfChannels(&self) -> u32 {
        self.number_of_channels
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-getchanneldata
    #[allow(unsafe_code)]
    unsafe fn GetChannelData(&self, cx: *mut JSContext, channel: u32) -> Fallible<NonNull<JSObject>> {
        if channel >= self.number_of_channels {
            return Err(Error::IndexSize);
        }

        if !self.restore_js_channel_data(cx) {
            return Err(Error::JSFailed);
        }

        Ok(NonNull::new_unchecked(self.js_channels.borrow()[channel as usize].get()))
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copyfromchannel
    #[allow(unsafe_code)]
    fn CopyFromChannel(&self,
                       mut destination: CustomAutoRooterGuard<Float32Array>,
                       channel_number: u32,
                       start_in_channel: u32) -> Fallible<()> {
        if channel_number >= self.number_of_channels || start_in_channel > self.length {
            return Err(Error::IndexSize);
        }

        let bytes_to_copy = min(self.length - start_in_channel, destination.len() as u32) as usize;
        let cx = self.global().get_cx();
        let channel_number = channel_number as usize;
        let offset = start_in_channel as usize;
        let mut dest = Vec::with_capacity(destination.len());
        // let destination = unsafe { destination.as_mut_slice() };

        // We either copy form js_channels or shared_channels.

        let js_channel = self.js_channels.borrow()[channel_number].get();
        if !js_channel.is_null() {
            typedarray!(in(cx) let array: Float32Array = js_channel);
            if let Ok(array) = array {
                let data = unsafe { array.as_slice() };
                dest.extend_from_slice(&data[offset..offset + bytes_to_copy]);
                return Ok(());
            }
        }

        if let Some(shared_channel) = self.shared_channels.borrow().buffers.get(channel_number) {
            dest.extend_from_slice(&shared_channel.as_slice()[offset..offset + bytes_to_copy]);
        }

        unsafe { destination.update(&dest); }

        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copytochannel
    #[allow(unsafe_code)]
    fn CopyToChannel(&self,
                     source: CustomAutoRooterGuard<Float32Array>,
                     channel_number: u32,
                     start_in_channel: u32) -> Fallible<()> {
        if channel_number >= self.number_of_channels || start_in_channel > (source.len() as u32) {
            return Err(Error::IndexSize);
        }

        let cx = self.global().get_cx();
        if !self.restore_js_channel_data(cx) {
            return Err(Error::JSFailed);
        }

        let js_channel = self.js_channels.borrow()[channel_number as usize].get();
        if js_channel.is_null() {
            // The array buffer was detached.
            return Err(Error::IndexSize);
        }

        typedarray!(in(cx) let array: Float32Array = js_channel);
        if let Ok(mut array) = array {
            let bytes_to_copy = min(self.length - start_in_channel, source.len() as u32) as usize;
            let offset = start_in_channel as usize;
            unsafe { array.update(&source.as_slice()[offset..offset + bytes_to_copy]); }
        } else {
            return Err(Error::IndexSize);
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>pub(crate) mod by_path;
pub(crate) mod custom_attr;

use protobuf::descriptor::EnumOptions;
use protobuf::descriptor::FieldOptions;
use protobuf::descriptor::FileOptions;
use protobuf::descriptor::MessageOptions;
use protobuf::rustproto;

/// Specifies style of generated code.
/// Generated files can be customized using this proto
/// or using `rustproto.proto` options.
#[derive(Default, Debug, Clone, PartialEq)]
pub struct Customize {
    /// Make oneof enum public.
    pub(crate) expose_oneof: Option<bool>,
    /// When true all fields are public, and accessors are not generated
    pub(crate) expose_fields: Option<bool>,
    /// When false, `get_`, `set_`, `mut_` etc. accessors are not generated
    pub(crate) generate_accessors: Option<bool>,
    /// When false, `get_` is not generated even if `syntax = "proto2"`
    pub(crate) generate_getter: Option<bool>,
    /// Use `bytes::Bytes` for `bytes` fields
    pub(crate) carllerche_bytes_for_bytes: Option<bool>,
    /// Use `bytes::Bytes` for `string` fields
    pub(crate) carllerche_bytes_for_string: Option<bool>,
    /// Implement serde_derive for messages
    pub(crate) serde_derive: Option<bool>,
    /// When `serde_derive` is set, serde annotations will be guarded with `#[cfg(cfg, ...)]`.
    pub(crate) serde_derive_cfg: Option<String>,
    /// When `serde_derive` is set, use attribute rename_all
    pub(crate) serde_rename_all: Option<String>,
    /// Enable lite runtime
    pub(crate) lite_runtime: Option<bool>,
    /// Generate `mod.rs` in the output directory.
    ///
    /// This option allows inclusion of generated files from cargo output directory.
    ///
    /// This option will likely be on by default in rust-protobuf version 3.
    pub(crate) gen_mod_rs: Option<bool>,
    /// Used internally to generate protos bundled in protobuf crate
    /// like `descriptor.proto`
    pub(crate) inside_protobuf: Option<bool>,
}

#[derive(Debug)]
pub enum CustomizeParseParameterError {
    EqNotFound,
    CannotParseBool,
    UnknownOptionName(String),
}

pub type CustomizeParseParameterResult<T> = Result<T, CustomizeParseParameterError>;

impl Customize {
    pub fn expose_oneof(mut self, expose_oneof: bool) -> Self {
        self.expose_oneof = Some(expose_oneof);
        self
    }

    pub fn expose_fields(mut self, expose_fields: bool) -> Self {
        self.expose_fields = Some(expose_fields);
        self
    }

    pub fn generate_accessors(mut self, generate_accessors: bool) -> Self {
        self.generate_accessors = Some(generate_accessors);
        self
    }

    pub fn generate_getter(mut self, generate_getter: bool) -> Self {
        self.generate_getter = Some(generate_getter);
        self
    }

    pub fn carllerche_bytes_for_bytes(mut self, carllerche_bytes_for_bytes: bool) -> Self {
        self.carllerche_bytes_for_bytes = Some(carllerche_bytes_for_bytes);
        self
    }

    pub fn carllerche_bytes_for_string(mut self, carllerche_bytes_for_string: bool) -> Self {
        self.carllerche_bytes_for_string = Some(carllerche_bytes_for_string);
        self
    }

    pub fn serde_derive(mut self, serde_derive: bool) -> Self {
        self.serde_derive = Some(serde_derive);
        self
    }

    pub fn serde_derive_cfg(mut self, serde_derive_cfg: &str) -> Self {
        self.serde_derive_cfg = Some(serde_derive_cfg.to_owned());
        self
    }

    pub fn serde_rename_all(mut self, serde_rename_all: &str) -> Self {
        self.serde_rename_all = Some(serde_rename_all.to_owned());
        self
    }

    pub fn lite_runtime(mut self, lite_runtime: bool) -> Self {
        self.lite_runtime = Some(lite_runtime);
        self
    }

    pub fn gen_mod_rs(mut self, gen_mod_rs: bool) -> Self {
        self.gen_mod_rs = Some(gen_mod_rs);
        self
    }

    pub fn inside_protobuf(mut self, inside_protobuf: bool) -> Self {
        self.inside_protobuf = Some(inside_protobuf);
        self
    }

    /// Update fields of self with fields defined in other customize
    pub fn update_with(&mut self, that: &Customize) {
        if let Some(v) = that.expose_oneof {
            self.expose_oneof = Some(v);
        }
        if let Some(v) = that.expose_fields {
            self.expose_fields = Some(v);
        }
        if let Some(v) = that.generate_accessors {
            self.generate_accessors = Some(v);
        }
        if let Some(v) = that.generate_getter {
            self.generate_getter = Some(v);
        }
        if let Some(v) = that.carllerche_bytes_for_bytes {
            self.carllerche_bytes_for_bytes = Some(v);
        }
        if let Some(v) = that.carllerche_bytes_for_string {
            self.carllerche_bytes_for_string = Some(v);
        }
        if let Some(v) = that.serde_derive {
            self.serde_derive = Some(v);
        }
        if let Some(ref v) = that.serde_derive_cfg {
            self.serde_derive_cfg = Some(v.clone());
        }
        if let Some(ref v) = that.serde_rename_all {
            self.serde_rename_all = Some(v.clone());
        }
        if let Some(v) = that.lite_runtime {
            self.lite_runtime = Some(v);
        }
        if let Some(v) = that.gen_mod_rs {
            self.gen_mod_rs = Some(v);
        }
        if let Some(v) = that.inside_protobuf {
            self.inside_protobuf = Some(v);
        }
    }

    /// Update unset fields of self with fields from other customize
    pub fn set_defaults_from(&mut self, other: &Customize) {
        let mut tmp = other.clone();
        tmp.update_with(self);
        *self = tmp;
    }

    /// Parse customize options from a string passed via protoc flag.
    pub fn parse_from_parameter(parameter: &str) -> CustomizeParseParameterResult<Customize> {
        fn parse_bool(v: &str) -> CustomizeParseParameterResult<bool> {
            v.parse()
                .map_err(|_| CustomizeParseParameterError::CannotParseBool)
        }

        let mut r = Customize::default();
        for nv in parameter.split_whitespace() {
            let eq = match nv.find('=') {
                Some(eq) => eq,
                None => return Err(CustomizeParseParameterError::EqNotFound),
            };

            let n = &nv[..eq];
            let v = &nv[eq + 1..];

            if n == "expose_oneof" {
                r.expose_oneof = Some(parse_bool(v)?);
            } else if n == "expose_fields" {
                r.expose_fields = Some(parse_bool(v)?);
            } else if n == "generate_accessors" {
                r.generate_accessors = Some(parse_bool(v)?);
            } else if n == "generate_getter" {
                r.generate_getter = Some(parse_bool(v)?);
            } else if n == "carllerche_bytes_for_bytes" {
                r.carllerche_bytes_for_bytes = Some(parse_bool(v)?);
            } else if n == "carllerche_bytes_for_string" {
                r.carllerche_bytes_for_string = Some(parse_bool(v)?);
            } else if n == "serde_derive" {
                r.serde_derive = Some(parse_bool(v)?);
            } else if n == "serde_derive_cfg" {
                r.serde_derive_cfg = Some(v.to_owned());
            } else if n == "serde_rename_all" {
                r.serde_rename_all = Some(v.to_owned());
            } else if n == "lite_runtime" {
                r.lite_runtime = Some(parse_bool(v)?);
            } else if n == "gen_mod_rs" {
                r.gen_mod_rs = Some(parse_bool(v)?);
            } else if n == "inside_protobuf" {
                r.inside_protobuf = Some(parse_bool(v)?);
            } else {
                return Err(CustomizeParseParameterError::UnknownOptionName(
                    n.to_owned(),
                ));
            }
        }
        Ok(r)
    }
}

pub fn customize_from_rustproto_for_message(source: &MessageOptions) -> Customize {
    let expose_oneof = rustproto::exts::expose_oneof.get(source);
    let expose_fields = rustproto::exts::expose_fields.get(source);
    let generate_accessors = rustproto::exts::generate_accessors.get(source);
    let generate_getter = rustproto::exts::generate_getter.get(source);
    let carllerche_bytes_for_bytes = rustproto::exts::carllerche_bytes_for_bytes.get(source);
    let carllerche_bytes_for_string = rustproto::exts::carllerche_bytes_for_string.get(source);
    let serde_derive = rustproto::exts::serde_derive.get(source);
    let serde_derive_cfg = rustproto::exts::serde_derive_cfg.get(source);
    let lite_runtime = None;
    let gen_mod_rs = None;
    let inside_protobuf = None;
    let serde_rename_all = None;
    Customize {
        expose_oneof,
        expose_fields,
        generate_accessors,
        generate_getter,
        carllerche_bytes_for_bytes,
        carllerche_bytes_for_string,
        serde_derive,
        serde_derive_cfg,
        serde_rename_all,
        lite_runtime,
        gen_mod_rs,
        inside_protobuf,
    }
}

pub fn customize_from_rustproto_for_enum(source: &EnumOptions) -> Customize {
    let serde_rename_all = rustproto::exts::serde_rename_all.get(source);
    let mut r = Customize::default();
    r.serde_rename_all = serde_rename_all;
    return r;
}

pub fn customize_from_rustproto_for_field(source: &FieldOptions) -> Customize {
    let expose_oneof = None;
    let expose_fields = rustproto::exts::expose_fields_field.get(source);
    let generate_accessors = rustproto::exts::generate_accessors_field.get(source);
    let generate_getter = rustproto::exts::generate_getter_field.get(source);
    let carllerche_bytes_for_bytes = rustproto::exts::carllerche_bytes_for_bytes_field.get(source);
    let carllerche_bytes_for_string =
        rustproto::exts::carllerche_bytes_for_string_field.get(source);
    let serde_rename_all = None;
    let serde_derive = None;
    let serde_derive_cfg = None;
    let lite_runtime = None;
    let gen_mod_rs = None;
    let inside_protobuf = None;
    Customize {
        expose_oneof,
        expose_fields,
        generate_accessors,
        generate_getter,
        carllerche_bytes_for_bytes,
        carllerche_bytes_for_string,
        serde_derive,
        serde_derive_cfg,
        serde_rename_all,
        lite_runtime,
        gen_mod_rs,
        inside_protobuf,
    }
}

pub fn customize_from_rustproto_for_file(source: &FileOptions) -> Customize {
    let expose_oneof = rustproto::exts::expose_oneof_all.get(source);
    let expose_fields = rustproto::exts::expose_fields_all.get(source);
    let generate_accessors = rustproto::exts::generate_accessors_all.get(source);
    let generate_getter = rustproto::exts::generate_getter_all.get(source);
    let carllerche_bytes_for_bytes = rustproto::exts::carllerche_bytes_for_bytes_all.get(source);
    let carllerche_bytes_for_string = rustproto::exts::carllerche_bytes_for_string_all.get(source);
    let serde_derive = rustproto::exts::serde_derive_all.get(source);
    let serde_derive_cfg = rustproto::exts::serde_derive_cfg_all.get(source);
    let lite_runtime = rustproto::exts::lite_runtime_all.get(source);
    let gen_mod_rs = None;
    let inside_protobuf = None;
    let serde_rename_all = None;
    Customize {
        expose_oneof,
        expose_fields,
        generate_accessors,
        generate_getter,
        carllerche_bytes_for_bytes,
        carllerche_bytes_for_string,
        serde_derive,
        serde_derive_cfg,
        serde_rename_all,
        lite_runtime,
        inside_protobuf,
        gen_mod_rs,
    }
}
<commit_msg>Dynamic customization of generated code<commit_after>pub(crate) mod by_path;
pub(crate) mod custom_attr;

use std::fmt;
use std::rc::Rc;

use protobuf::descriptor::EnumOptions;
use protobuf::descriptor::FieldOptions;
use protobuf::descriptor::FileOptions;
use protobuf::descriptor::MessageOptions;
use protobuf::reflect::EnumDescriptor;
use protobuf::reflect::FieldDescriptor;
use protobuf::reflect::MessageDescriptor;
use protobuf::reflect::OneofDescriptor;
use protobuf::rustproto;

/// Dynamic callback to customize code generation.
pub trait CustomizeCallback: 'static {
    fn customize_message(&self, message: &MessageDescriptor) -> String {
        let _ = message;
        String::new()
    }

    fn customize_field(&self, field: &FieldDescriptor) -> String {
        let _ = field;
        String::new()
    }

    fn customize_special_field(&self, message: &MessageDescriptor, field: &str) -> String {
        let _ = (message, field);
        String::new()
    }

    fn customize_enum(&self, enum_type: &EnumDescriptor) -> String {
        let _ = enum_type;
        String::new()
    }

    fn customize_oneof(&self, oneof: &OneofDescriptor) -> String {
        let _ = oneof;
        String::new()
    }
}

#[derive(Clone)]
pub(crate) struct CustomizeCallbackHolder(pub(crate) Rc<dyn CustomizeCallback>);

impl PartialEq for CustomizeCallbackHolder {
    fn eq(&self, other: &Self) -> bool {
        Rc::ptr_eq(&self.0, &other.0)
    }
}

impl fmt::Debug for CustomizeCallbackHolder {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("CustomizeCallbackWrapper")
            .finish_non_exhaustive()
    }
}

/// Specifies style of generated code.
/// Generated files can be customized using this proto
/// or using `rustproto.proto` options.
#[derive(Default, Debug, Clone, PartialEq)]
pub struct Customize {
    /// Make oneof enum public.
    pub(crate) expose_oneof: Option<bool>,
    /// When true all fields are public, and accessors are not generated
    pub(crate) expose_fields: Option<bool>,
    /// When false, `get_`, `set_`, `mut_` etc. accessors are not generated
    pub(crate) generate_accessors: Option<bool>,
    /// When false, `get_` is not generated even if `syntax = "proto2"`
    pub(crate) generate_getter: Option<bool>,
    /// Use `bytes::Bytes` for `bytes` fields
    pub(crate) carllerche_bytes_for_bytes: Option<bool>,
    /// Use `bytes::Bytes` for `string` fields
    pub(crate) carllerche_bytes_for_string: Option<bool>,
    /// Implement serde_derive for messages
    pub(crate) serde_derive: Option<bool>,
    /// When `serde_derive` is set, serde annotations will be guarded with `#[cfg(cfg, ...)]`.
    pub(crate) serde_derive_cfg: Option<String>,
    /// When `serde_derive` is set, use attribute rename_all
    pub(crate) serde_rename_all: Option<String>,
    /// Enable lite runtime
    pub(crate) lite_runtime: Option<bool>,
    /// Generate `mod.rs` in the output directory.
    ///
    /// This option allows inclusion of generated files from cargo output directory.
    ///
    /// This option will likely be on by default in rust-protobuf version 3.
    pub(crate) gen_mod_rs: Option<bool>,
    /// Used internally to generate protos bundled in protobuf crate
    /// like `descriptor.proto`
    pub(crate) inside_protobuf: Option<bool>,
    /// Dynamically alter generated code.
    pub(crate) callback: Option<CustomizeCallbackHolder>,
}

#[derive(Debug)]
pub enum CustomizeParseParameterError {
    EqNotFound,
    CannotParseBool,
    UnknownOptionName(String),
}

pub type CustomizeParseParameterResult<T> = Result<T, CustomizeParseParameterError>;

impl Customize {
    pub fn expose_oneof(mut self, expose_oneof: bool) -> Self {
        self.expose_oneof = Some(expose_oneof);
        self
    }

    pub fn expose_fields(mut self, expose_fields: bool) -> Self {
        self.expose_fields = Some(expose_fields);
        self
    }

    pub fn generate_accessors(mut self, generate_accessors: bool) -> Self {
        self.generate_accessors = Some(generate_accessors);
        self
    }

    pub fn generate_getter(mut self, generate_getter: bool) -> Self {
        self.generate_getter = Some(generate_getter);
        self
    }

    pub fn carllerche_bytes_for_bytes(mut self, carllerche_bytes_for_bytes: bool) -> Self {
        self.carllerche_bytes_for_bytes = Some(carllerche_bytes_for_bytes);
        self
    }

    pub fn carllerche_bytes_for_string(mut self, carllerche_bytes_for_string: bool) -> Self {
        self.carllerche_bytes_for_string = Some(carllerche_bytes_for_string);
        self
    }

    pub fn serde_derive(mut self, serde_derive: bool) -> Self {
        self.serde_derive = Some(serde_derive);
        self
    }

    pub fn serde_derive_cfg(mut self, serde_derive_cfg: &str) -> Self {
        self.serde_derive_cfg = Some(serde_derive_cfg.to_owned());
        self
    }

    pub fn serde_rename_all(mut self, serde_rename_all: &str) -> Self {
        self.serde_rename_all = Some(serde_rename_all.to_owned());
        self
    }

    pub fn lite_runtime(mut self, lite_runtime: bool) -> Self {
        self.lite_runtime = Some(lite_runtime);
        self
    }

    pub fn gen_mod_rs(mut self, gen_mod_rs: bool) -> Self {
        self.gen_mod_rs = Some(gen_mod_rs);
        self
    }

    pub fn inside_protobuf(mut self, inside_protobuf: bool) -> Self {
        self.inside_protobuf = Some(inside_protobuf);
        self
    }

    pub fn callback(mut self, callback: impl CustomizeCallback) -> Self {
        self.callback = Some(CustomizeCallbackHolder(Rc::new(callback)));
        self
    }

    /// Update fields of self with fields defined in other customize
    pub fn update_with(&mut self, that: &Customize) {
        if let Some(v) = that.expose_oneof {
            self.expose_oneof = Some(v);
        }
        if let Some(v) = that.expose_fields {
            self.expose_fields = Some(v);
        }
        if let Some(v) = that.generate_accessors {
            self.generate_accessors = Some(v);
        }
        if let Some(v) = that.generate_getter {
            self.generate_getter = Some(v);
        }
        if let Some(v) = that.carllerche_bytes_for_bytes {
            self.carllerche_bytes_for_bytes = Some(v);
        }
        if let Some(v) = that.carllerche_bytes_for_string {
            self.carllerche_bytes_for_string = Some(v);
        }
        if let Some(v) = that.serde_derive {
            self.serde_derive = Some(v);
        }
        if let Some(ref v) = that.serde_derive_cfg {
            self.serde_derive_cfg = Some(v.clone());
        }
        if let Some(ref v) = that.serde_rename_all {
            self.serde_rename_all = Some(v.clone());
        }
        if let Some(v) = that.lite_runtime {
            self.lite_runtime = Some(v);
        }
        if let Some(v) = that.gen_mod_rs {
            self.gen_mod_rs = Some(v);
        }
        if let Some(v) = that.inside_protobuf {
            self.inside_protobuf = Some(v);
        }
    }

    /// Update unset fields of self with fields from other customize
    pub fn set_defaults_from(&mut self, other: &Customize) {
        let mut tmp = other.clone();
        tmp.update_with(self);
        *self = tmp;
    }

    /// Parse customize options from a string passed via protoc flag.
    pub fn parse_from_parameter(parameter: &str) -> CustomizeParseParameterResult<Customize> {
        fn parse_bool(v: &str) -> CustomizeParseParameterResult<bool> {
            v.parse()
                .map_err(|_| CustomizeParseParameterError::CannotParseBool)
        }

        let mut r = Customize::default();
        for nv in parameter.split_whitespace() {
            let eq = match nv.find('=') {
                Some(eq) => eq,
                None => return Err(CustomizeParseParameterError::EqNotFound),
            };

            let n = &nv[..eq];
            let v = &nv[eq + 1..];

            if n == "expose_oneof" {
                r.expose_oneof = Some(parse_bool(v)?);
            } else if n == "expose_fields" {
                r.expose_fields = Some(parse_bool(v)?);
            } else if n == "generate_accessors" {
                r.generate_accessors = Some(parse_bool(v)?);
            } else if n == "generate_getter" {
                r.generate_getter = Some(parse_bool(v)?);
            } else if n == "carllerche_bytes_for_bytes" {
                r.carllerche_bytes_for_bytes = Some(parse_bool(v)?);
            } else if n == "carllerche_bytes_for_string" {
                r.carllerche_bytes_for_string = Some(parse_bool(v)?);
            } else if n == "serde_derive" {
                r.serde_derive = Some(parse_bool(v)?);
            } else if n == "serde_derive_cfg" {
                r.serde_derive_cfg = Some(v.to_owned());
            } else if n == "serde_rename_all" {
                r.serde_rename_all = Some(v.to_owned());
            } else if n == "lite_runtime" {
                r.lite_runtime = Some(parse_bool(v)?);
            } else if n == "gen_mod_rs" {
                r.gen_mod_rs = Some(parse_bool(v)?);
            } else if n == "inside_protobuf" {
                r.inside_protobuf = Some(parse_bool(v)?);
            } else {
                return Err(CustomizeParseParameterError::UnknownOptionName(
                    n.to_owned(),
                ));
            }
        }
        Ok(r)
    }
}

pub fn customize_from_rustproto_for_message(source: &MessageOptions) -> Customize {
    let expose_oneof = rustproto::exts::expose_oneof.get(source);
    let expose_fields = rustproto::exts::expose_fields.get(source);
    let generate_accessors = rustproto::exts::generate_accessors.get(source);
    let generate_getter = rustproto::exts::generate_getter.get(source);
    let carllerche_bytes_for_bytes = rustproto::exts::carllerche_bytes_for_bytes.get(source);
    let carllerche_bytes_for_string = rustproto::exts::carllerche_bytes_for_string.get(source);
    let serde_derive = rustproto::exts::serde_derive.get(source);
    let serde_derive_cfg = rustproto::exts::serde_derive_cfg.get(source);
    let lite_runtime = None;
    let gen_mod_rs = None;
    let inside_protobuf = None;
    let serde_rename_all = None;
    let callback = None;
    Customize {
        expose_oneof,
        expose_fields,
        generate_accessors,
        generate_getter,
        carllerche_bytes_for_bytes,
        carllerche_bytes_for_string,
        serde_derive,
        serde_derive_cfg,
        serde_rename_all,
        lite_runtime,
        gen_mod_rs,
        inside_protobuf,
        callback,
    }
}

pub fn customize_from_rustproto_for_enum(source: &EnumOptions) -> Customize {
    let serde_rename_all = rustproto::exts::serde_rename_all.get(source);
    let mut r = Customize::default();
    r.serde_rename_all = serde_rename_all;
    return r;
}

pub fn customize_from_rustproto_for_field(source: &FieldOptions) -> Customize {
    let expose_oneof = None;
    let expose_fields = rustproto::exts::expose_fields_field.get(source);
    let generate_accessors = rustproto::exts::generate_accessors_field.get(source);
    let generate_getter = rustproto::exts::generate_getter_field.get(source);
    let carllerche_bytes_for_bytes = rustproto::exts::carllerche_bytes_for_bytes_field.get(source);
    let carllerche_bytes_for_string =
        rustproto::exts::carllerche_bytes_for_string_field.get(source);
    let serde_rename_all = None;
    let serde_derive = None;
    let serde_derive_cfg = None;
    let lite_runtime = None;
    let gen_mod_rs = None;
    let inside_protobuf = None;
    let callback = None;
    Customize {
        expose_oneof,
        expose_fields,
        generate_accessors,
        generate_getter,
        carllerche_bytes_for_bytes,
        carllerche_bytes_for_string,
        serde_derive,
        serde_derive_cfg,
        serde_rename_all,
        lite_runtime,
        gen_mod_rs,
        inside_protobuf,
        callback,
    }
}

pub fn customize_from_rustproto_for_file(source: &FileOptions) -> Customize {
    let expose_oneof = rustproto::exts::expose_oneof_all.get(source);
    let expose_fields = rustproto::exts::expose_fields_all.get(source);
    let generate_accessors = rustproto::exts::generate_accessors_all.get(source);
    let generate_getter = rustproto::exts::generate_getter_all.get(source);
    let carllerche_bytes_for_bytes = rustproto::exts::carllerche_bytes_for_bytes_all.get(source);
    let carllerche_bytes_for_string = rustproto::exts::carllerche_bytes_for_string_all.get(source);
    let serde_derive = rustproto::exts::serde_derive_all.get(source);
    let serde_derive_cfg = rustproto::exts::serde_derive_cfg_all.get(source);
    let lite_runtime = rustproto::exts::lite_runtime_all.get(source);
    let gen_mod_rs = None;
    let inside_protobuf = None;
    let serde_rename_all = None;
    let callback = None;
    Customize {
        expose_oneof,
        expose_fields,
        generate_accessors,
        generate_getter,
        carllerche_bytes_for_bytes,
        carllerche_bytes_for_string,
        serde_derive,
        serde_derive_cfg,
        serde_rename_all,
        lite_runtime,
        inside_protobuf,
        gen_mod_rs,
        callback,
    }
}
<|endoftext|>


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

use devtools_traits::ScriptToDevtoolsControlMsg;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::Root;
use dom::globalscope::GlobalScope;
use dom::paintworkletglobalscope::PaintWorkletGlobalScope;
use dom::paintworkletglobalscope::PaintWorkletTask;
use dom::testworkletglobalscope::TestWorkletGlobalScope;
use dom::testworkletglobalscope::TestWorkletTask;
use dom::worklet::WorkletExecutor;
use dom_struct::dom_struct;
use ipc_channel::ipc;
use ipc_channel::ipc::IpcSender;
use js::jsapi::JSContext;
use js::jsval::UndefinedValue;
use js::rust::Runtime;
use microtask::Microtask;
use microtask::MicrotaskQueue;
use msg::constellation_msg::PipelineId;
use net_traits::ResourceThreads;
use net_traits::image_cache::ImageCache;
use profile_traits::mem;
use profile_traits::time;
use script_layout_interface::message::Msg;
use script_runtime::CommonScriptMsg;
use script_runtime::ScriptThreadEventCategory;
use script_thread::MainThreadScriptMsg;
use script_thread::Runnable;
use script_thread::ScriptThread;
use script_traits::ScriptMsg;
use script_traits::ScriptToConstellationChan;
use script_traits::TimerSchedulerMsg;
use servo_url::ImmutableOrigin;
use servo_url::MutableOrigin;
use servo_url::ServoUrl;
use std::sync::Arc;
use std::sync::mpsc::Sender;

#[dom_struct]
/// https://drafts.css-houdini.org/worklets/#workletglobalscope
pub struct WorkletGlobalScope {
    /// The global for this worklet.
    globalscope: GlobalScope,
    /// The base URL for this worklet.
    base_url: ServoUrl,
    /// The microtask queue for this worklet
    microtask_queue: MicrotaskQueue,
    /// Sender back to the script thread
    #[ignore_heap_size_of = "channels are hard"]
    to_script_thread_sender: Sender<MainThreadScriptMsg>,
    /// Worklet task executor
    executor: WorkletExecutor,
}

impl WorkletGlobalScope {
    /// Create a new stack-allocated `WorkletGlobalScope`.
    pub fn new_inherited(pipeline_id: PipelineId,
                         base_url: ServoUrl,
                         executor: WorkletExecutor,
                         init: &WorkletGlobalScopeInit)
                         -> WorkletGlobalScope {
        // Any timer events fired on this global are ignored.
        let (timer_event_chan, _) = ipc::channel().unwrap();
        let script_to_constellation_chan = ScriptToConstellationChan {
            sender: init.to_constellation_sender.clone(),
            pipeline_id: pipeline_id,
        };
        WorkletGlobalScope {
            globalscope: GlobalScope::new_inherited(pipeline_id,
                                                    init.devtools_chan.clone(),
                                                    init.mem_profiler_chan.clone(),
                                                    init.time_profiler_chan.clone(),
                                                    script_to_constellation_chan,
                                                    init.scheduler_chan.clone(),
                                                    init.resource_threads.clone(),
                                                    timer_event_chan,
                                                    MutableOrigin::new(ImmutableOrigin::new_opaque())),
            base_url: base_url,
            microtask_queue: MicrotaskQueue::default(),
            to_script_thread_sender: init.to_script_thread_sender.clone(),
            executor: executor,
        }
    }

    /// Get the JS context.
    pub fn get_cx(&self) -> *mut JSContext {
        self.globalscope.get_cx()
    }

    /// Evaluate a JS script in this global.
    pub fn evaluate_js(&self, script: &str) -> bool {
        debug!("Evaluating JS.");
        rooted!(in (self.globalscope.get_cx()) let mut rval = UndefinedValue());
        self.globalscope.evaluate_js_on_global_with_result(&*script, rval.handle_mut())
    }

    /// Run a runnable in the main script thread.
    pub fn run_in_script_thread<R>(&self, runnable: R) where
        R: 'static + Send + Runnable,
    {
        let msg = CommonScriptMsg::RunnableMsg(ScriptThreadEventCategory::WorkletEvent, box runnable);
        let msg = MainThreadScriptMsg::Common(msg);
        self.to_script_thread_sender.send(msg).expect("Worklet thread outlived script thread.");
    }

    /// Send a message to layout.
    pub fn send_to_layout(&self, msg: Msg) {
        struct RunnableMsg(PipelineId, Msg);
        impl Runnable for RunnableMsg {
            fn main_thread_handler(self: Box<Self>, script_thread: &ScriptThread) {
                script_thread.send_to_layout(self.0, self.1);
            }
        }
        let pipeline_id = self.globalscope.pipeline_id();
        self.run_in_script_thread(RunnableMsg(pipeline_id, msg));
    }

    /// The base URL of this global.
    pub fn base_url(&self) -> ServoUrl {
        self.base_url.clone()
    }

    /// The worklet executor.
    pub fn executor(&self) -> WorkletExecutor {
        self.executor.clone()
    }

    /// Queue up a microtask to be executed in this global.
    pub fn enqueue_microtask(&self, job: Microtask) {
        self.microtask_queue.enqueue(job);
    }

    /// Perform any queued microtasks.
    pub fn perform_a_microtask_checkpoint(&self) {
        self.microtask_queue.checkpoint(|id| {
            let global = self.upcast::<GlobalScope>();
            assert_eq!(global.pipeline_id(), id);
            Some(Root::from_ref(global))
        });
    }

    /// Perform a worklet task
    pub fn perform_a_worklet_task(&self, task: WorkletTask) {
        match task {
            WorkletTask::Test(task) => match self.downcast::<TestWorkletGlobalScope>() {
                Some(global) => global.perform_a_worklet_task(task),
                None => warn!("This is not a test worklet."),
            },
            WorkletTask::Paint(task) => match self.downcast::<PaintWorkletGlobalScope>() {
                Some(global) => global.perform_a_worklet_task(task),
                None => warn!("This is not a paint worklet."),
            },
        }
    }
}

/// Resources required by workletglobalscopes
#[derive(Clone)]
pub struct WorkletGlobalScopeInit {
    /// Channel to the main script thread
    pub to_script_thread_sender: Sender<MainThreadScriptMsg>,
    /// Channel to a resource thread
    pub resource_threads: ResourceThreads,
    /// Channel to the memory profiler
    pub mem_profiler_chan: mem::ProfilerChan,
    /// Channel to the time profiler
    pub time_profiler_chan: time::ProfilerChan,
    /// Channel to devtools
    pub devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
    /// Messages to send to constellation
    pub to_constellation_sender: IpcSender<(PipelineId, ScriptMsg)>,
    /// Message to send to the scheduler
    pub scheduler_chan: IpcSender<TimerSchedulerMsg>,
    /// The image cache
    pub image_cache: Arc<ImageCache>,
}

/// https://drafts.css-houdini.org/worklets/#worklet-global-scope-type
#[derive(Clone, Copy, Debug, HeapSizeOf, JSTraceable)]
pub enum WorkletGlobalScopeType {
    /// A servo-specific testing worklet
    Test,
    /// A paint worklet
    Paint,
}

impl WorkletGlobalScopeType {
    /// Create a new heap-allocated `WorkletGlobalScope`.
    pub fn new(&self,
               runtime: &Runtime,
               pipeline_id: PipelineId,
               base_url: ServoUrl,
               executor: WorkletExecutor,
               init: &WorkletGlobalScopeInit)
               -> Root<WorkletGlobalScope>
    {
        match *self {
            WorkletGlobalScopeType::Test =>
                Root::upcast(TestWorkletGlobalScope::new(runtime, pipeline_id, base_url, executor, init)),
            WorkletGlobalScopeType::Paint =>
                Root::upcast(PaintWorkletGlobalScope::new(runtime, pipeline_id, base_url, executor, init)),
        }
    }
}

/// A task which can be performed in the context of a worklet global.
pub enum WorkletTask {
    Test(TestWorkletTask),
    Paint(PaintWorkletTask),
}
<commit_msg>Reformat WorkletGlobalScope::new_inherited<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use devtools_traits::ScriptToDevtoolsControlMsg;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::Root;
use dom::globalscope::GlobalScope;
use dom::paintworkletglobalscope::PaintWorkletGlobalScope;
use dom::paintworkletglobalscope::PaintWorkletTask;
use dom::testworkletglobalscope::TestWorkletGlobalScope;
use dom::testworkletglobalscope::TestWorkletTask;
use dom::worklet::WorkletExecutor;
use dom_struct::dom_struct;
use ipc_channel::ipc;
use ipc_channel::ipc::IpcSender;
use js::jsapi::JSContext;
use js::jsval::UndefinedValue;
use js::rust::Runtime;
use microtask::Microtask;
use microtask::MicrotaskQueue;
use msg::constellation_msg::PipelineId;
use net_traits::ResourceThreads;
use net_traits::image_cache::ImageCache;
use profile_traits::mem;
use profile_traits::time;
use script_layout_interface::message::Msg;
use script_runtime::CommonScriptMsg;
use script_runtime::ScriptThreadEventCategory;
use script_thread::MainThreadScriptMsg;
use script_thread::Runnable;
use script_thread::ScriptThread;
use script_traits::ScriptMsg;
use script_traits::ScriptToConstellationChan;
use script_traits::TimerSchedulerMsg;
use servo_url::ImmutableOrigin;
use servo_url::MutableOrigin;
use servo_url::ServoUrl;
use std::sync::Arc;
use std::sync::mpsc::Sender;

#[dom_struct]
/// https://drafts.css-houdini.org/worklets/#workletglobalscope
pub struct WorkletGlobalScope {
    /// The global for this worklet.
    globalscope: GlobalScope,
    /// The base URL for this worklet.
    base_url: ServoUrl,
    /// The microtask queue for this worklet
    microtask_queue: MicrotaskQueue,
    /// Sender back to the script thread
    #[ignore_heap_size_of = "channels are hard"]
    to_script_thread_sender: Sender<MainThreadScriptMsg>,
    /// Worklet task executor
    executor: WorkletExecutor,
}

impl WorkletGlobalScope {
    /// Create a new stack-allocated `WorkletGlobalScope`.
    pub fn new_inherited(
        pipeline_id: PipelineId,
        base_url: ServoUrl,
        executor: WorkletExecutor,
        init: &WorkletGlobalScopeInit,
    ) -> Self {
        // Any timer events fired on this global are ignored.
        let (timer_event_chan, _) = ipc::channel().unwrap();
        let script_to_constellation_chan = ScriptToConstellationChan {
            sender: init.to_constellation_sender.clone(),
            pipeline_id,
        };
        Self {
            globalscope: GlobalScope::new_inherited(
                pipeline_id,
                init.devtools_chan.clone(),
                init.mem_profiler_chan.clone(),
                init.time_profiler_chan.clone(),
                script_to_constellation_chan,
                init.scheduler_chan.clone(),
                init.resource_threads.clone(),
                timer_event_chan,
                MutableOrigin::new(ImmutableOrigin::new_opaque()),
            ),
            base_url,
            microtask_queue: Default::default(),
            to_script_thread_sender: init.to_script_thread_sender.clone(),
            executor,
        }
    }

    /// Get the JS context.
    pub fn get_cx(&self) -> *mut JSContext {
        self.globalscope.get_cx()
    }

    /// Evaluate a JS script in this global.
    pub fn evaluate_js(&self, script: &str) -> bool {
        debug!("Evaluating JS.");
        rooted!(in (self.globalscope.get_cx()) let mut rval = UndefinedValue());
        self.globalscope.evaluate_js_on_global_with_result(&*script, rval.handle_mut())
    }

    /// Run a runnable in the main script thread.
    pub fn run_in_script_thread<R>(&self, runnable: R) where
        R: 'static + Send + Runnable,
    {
        let msg = CommonScriptMsg::RunnableMsg(ScriptThreadEventCategory::WorkletEvent, box runnable);
        let msg = MainThreadScriptMsg::Common(msg);
        self.to_script_thread_sender.send(msg).expect("Worklet thread outlived script thread.");
    }

    /// Send a message to layout.
    pub fn send_to_layout(&self, msg: Msg) {
        struct RunnableMsg(PipelineId, Msg);
        impl Runnable for RunnableMsg {
            fn main_thread_handler(self: Box<Self>, script_thread: &ScriptThread) {
                script_thread.send_to_layout(self.0, self.1);
            }
        }
        let pipeline_id = self.globalscope.pipeline_id();
        self.run_in_script_thread(RunnableMsg(pipeline_id, msg));
    }

    /// The base URL of this global.
    pub fn base_url(&self) -> ServoUrl {
        self.base_url.clone()
    }

    /// The worklet executor.
    pub fn executor(&self) -> WorkletExecutor {
        self.executor.clone()
    }

    /// Queue up a microtask to be executed in this global.
    pub fn enqueue_microtask(&self, job: Microtask) {
        self.microtask_queue.enqueue(job);
    }

    /// Perform any queued microtasks.
    pub fn perform_a_microtask_checkpoint(&self) {
        self.microtask_queue.checkpoint(|id| {
            let global = self.upcast::<GlobalScope>();
            assert_eq!(global.pipeline_id(), id);
            Some(Root::from_ref(global))
        });
    }

    /// Perform a worklet task
    pub fn perform_a_worklet_task(&self, task: WorkletTask) {
        match task {
            WorkletTask::Test(task) => match self.downcast::<TestWorkletGlobalScope>() {
                Some(global) => global.perform_a_worklet_task(task),
                None => warn!("This is not a test worklet."),
            },
            WorkletTask::Paint(task) => match self.downcast::<PaintWorkletGlobalScope>() {
                Some(global) => global.perform_a_worklet_task(task),
                None => warn!("This is not a paint worklet."),
            },
        }
    }
}

/// Resources required by workletglobalscopes
#[derive(Clone)]
pub struct WorkletGlobalScopeInit {
    /// Channel to the main script thread
    pub to_script_thread_sender: Sender<MainThreadScriptMsg>,
    /// Channel to a resource thread
    pub resource_threads: ResourceThreads,
    /// Channel to the memory profiler
    pub mem_profiler_chan: mem::ProfilerChan,
    /// Channel to the time profiler
    pub time_profiler_chan: time::ProfilerChan,
    /// Channel to devtools
    pub devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
    /// Messages to send to constellation
    pub to_constellation_sender: IpcSender<(PipelineId, ScriptMsg)>,
    /// Message to send to the scheduler
    pub scheduler_chan: IpcSender<TimerSchedulerMsg>,
    /// The image cache
    pub image_cache: Arc<ImageCache>,
}

/// https://drafts.css-houdini.org/worklets/#worklet-global-scope-type
#[derive(Clone, Copy, Debug, HeapSizeOf, JSTraceable)]
pub enum WorkletGlobalScopeType {
    /// A servo-specific testing worklet
    Test,
    /// A paint worklet
    Paint,
}

impl WorkletGlobalScopeType {
    /// Create a new heap-allocated `WorkletGlobalScope`.
    pub fn new(&self,
               runtime: &Runtime,
               pipeline_id: PipelineId,
               base_url: ServoUrl,
               executor: WorkletExecutor,
               init: &WorkletGlobalScopeInit)
               -> Root<WorkletGlobalScope>
    {
        match *self {
            WorkletGlobalScopeType::Test =>
                Root::upcast(TestWorkletGlobalScope::new(runtime, pipeline_id, base_url, executor, init)),
            WorkletGlobalScopeType::Paint =>
                Root::upcast(PaintWorkletGlobalScope::new(runtime, pipeline_id, base_url, executor, init)),
        }
    }
}

/// A task which can be performed in the context of a worklet global.
pub enum WorkletTask {
    Test(TestWorkletTask),
    Paint(PaintWorkletTask),
}
<|endoftext|>


<commit_before>// Copyright 2016 bluss and ndarray developers.
//
// 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.

extern crate rand;
extern crate ndarray;

use std::iter::FromIterator;

use rand::Rng;
use rand::distributions::Sample;
use rand::distributions::IndependentSample;

use ndarray::{
    ArrayBase,
    Dimension,
    DataOwned,
};
use ndarray::IntoShape;

/// Constructors for n-dimensional arrays with random elements.
///
/// This trait extends ndarray’s `ArrayBase` and can not be implemented
/// for other types.
///
/// The default Rng is a fast automatically seeded rng (currently `rand::weak_rng`).
pub trait RandomExt<S, D>
    where S: DataOwned,
          D: Dimension,
{
    /// Create an array with shape `dim` with elements drawn from
    /// `distribution`  using the default rng.
    ///
    /// ***Panics*** if the number of elements overflows usize.
    ///
    /// ```
    /// extern crate rand;
    /// extern crate ndarray;
    /// extern crate ndarray_rand;
    ///
    /// use rand::distributions::Range;
    /// use ndarray::Array;
    /// use ndarray_rand::RandomExt;
    ///
    /// # fn main() {
    /// let a = Array::random((2, 5), Range::new(0., 10.));
    /// println!("{:8.4}", a);
    /// // Example Output:
    /// // [[  8.6900,   6.9824,   3.8922,   6.5861,   2.4890],
    /// //  [  0.0914,   5.5186,   5.8135,   5.2361,   3.1879]]
    /// # }
    fn random<Sh, IdS>(shape: Sh, distribution: IdS) -> ArrayBase<S, D>
        where IdS: IndependentSample<S::Elem>,
              Sh: IntoShape<Dim=D>;

    /// Create an array with shape `dim` with elements drawn from
    /// `distribution`, using a specific Rng `rng`.
    ///
    /// ***Panics*** if the number of elements overflows usize.
    fn random_using<Sh, IdS, R>(shape: Sh, distribution: IdS, rng: &mut R) -> ArrayBase<S, D>
        where IdS: IndependentSample<S::Elem>,
              R: Rng,
              Sh: IntoShape<Dim=D>;
}

impl<S, D> RandomExt<S, D> for ArrayBase<S, D>
    where S: DataOwned,
          D: Dimension,
{
    fn random<Sh, IdS>(shape: Sh, dist: IdS) -> ArrayBase<S, D>
        where IdS: IndependentSample<S::Elem>,
              Sh: IntoShape<Dim=D>,
    {
        Self::random_using(shape, dist, &mut rand::weak_rng())
    }

    fn random_using<Sh, IdS, R>(shape: Sh, dist: IdS, rng: &mut R) -> ArrayBase<S, D>
        where IdS: IndependentSample<S::Elem>,
              R: Rng,
              Sh: IntoShape<Dim=D>,
    {
        let shape = shape.into_shape();
        let elements = Vec::from_iter((0..shape.size()).map(move |_| dist.ind_sample(rng)));
        Self::from_shape_vec(shape, elements).unwrap()
    }
}

/// A wrapper type that allows casting f64 distributions to f32
///
/// ```
/// extern crate rand;
/// extern crate ndarray;
/// extern crate ndarray_rand;
///
/// use rand::distributions::Normal;
/// use ndarray::Array;
/// use ndarray_rand::{RandomExt, F32};
///
/// # fn main() {
/// let a = Array::random((2, 5), F32(Normal::new(0., 1.)));
/// println!("{:8.4}", a);
/// // Example Output:
/// // [[ -0.6910,   1.1730,   1.0902,  -0.4092,  -1.7340],
/// //  [ -0.6810,   0.1678,  -0.9487,   0.3150,   1.2981]]
/// # }
#[derive(Copy, Clone, Debug)]
pub struct F32<S>(pub S);

impl<S> Sample<f32> for F32<S>
    where S: Sample<f64>
{
    fn sample<R>(&mut self, rng: &mut R) -> f32 where R: Rng {
        self.0.sample(rng) as f32
    }
}

impl<S> IndependentSample<f32> for F32<S>
    where S: IndependentSample<f64>
{
    fn ind_sample<R>(&self, rng: &mut R) -> f32 where R: Rng {
        self.0.ind_sample(rng) as f32
    }
}
<commit_msg>ndarray-rand: Migrate to ShapeBuilder<commit_after>// Copyright 2016 bluss and ndarray developers.
//
// 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.

extern crate rand;
extern crate ndarray;

use std::iter::FromIterator;

use rand::Rng;
use rand::distributions::Sample;
use rand::distributions::IndependentSample;

use ndarray::{
    ArrayBase,
    Dimension,
    DataOwned,
};
use ndarray::ShapeBuilder;

/// Constructors for n-dimensional arrays with random elements.
///
/// This trait extends ndarray’s `ArrayBase` and can not be implemented
/// for other types.
///
/// The default Rng is a fast automatically seeded rng (currently `rand::weak_rng`).
pub trait RandomExt<S, D>
    where S: DataOwned,
          D: Dimension,
{
    /// Create an array with shape `dim` with elements drawn from
    /// `distribution`  using the default rng.
    ///
    /// ***Panics*** if the number of elements overflows usize.
    ///
    /// ```
    /// extern crate rand;
    /// extern crate ndarray;
    /// extern crate ndarray_rand;
    ///
    /// use rand::distributions::Range;
    /// use ndarray::Array;
    /// use ndarray_rand::RandomExt;
    ///
    /// # fn main() {
    /// let a = Array::random((2, 5), Range::new(0., 10.));
    /// println!("{:8.4}", a);
    /// // Example Output:
    /// // [[  8.6900,   6.9824,   3.8922,   6.5861,   2.4890],
    /// //  [  0.0914,   5.5186,   5.8135,   5.2361,   3.1879]]
    /// # }
    fn random<Sh, IdS>(shape: Sh, distribution: IdS) -> ArrayBase<S, D>
        where IdS: IndependentSample<S::Elem>,
              Sh: ShapeBuilder<Dim=D>;

    /// Create an array with shape `dim` with elements drawn from
    /// `distribution`, using a specific Rng `rng`.
    ///
    /// ***Panics*** if the number of elements overflows usize.
    fn random_using<Sh, IdS, R>(shape: Sh, distribution: IdS, rng: &mut R) -> ArrayBase<S, D>
        where IdS: IndependentSample<S::Elem>,
              R: Rng,
              Sh: ShapeBuilder<Dim=D>;
}

impl<S, D> RandomExt<S, D> for ArrayBase<S, D>
    where S: DataOwned,
          D: Dimension,
{
    fn random<Sh, IdS>(shape: Sh, dist: IdS) -> ArrayBase<S, D>
        where IdS: IndependentSample<S::Elem>,
              Sh: ShapeBuilder<Dim=D>,
    {
        Self::random_using(shape, dist, &mut rand::weak_rng())
    }

    fn random_using<Sh, IdS, R>(shape: Sh, dist: IdS, rng: &mut R) -> ArrayBase<S, D>
        where IdS: IndependentSample<S::Elem>,
              R: Rng,
              Sh: ShapeBuilder<Dim=D>,
    {
        let shape = shape.into_shape();
        let elements = Vec::from_iter((0..shape.size()).map(move |_| dist.ind_sample(rng)));
        Self::from_shape_vec(shape, elements).unwrap()
    }
}

/// A wrapper type that allows casting f64 distributions to f32
///
/// ```
/// extern crate rand;
/// extern crate ndarray;
/// extern crate ndarray_rand;
///
/// use rand::distributions::Normal;
/// use ndarray::Array;
/// use ndarray_rand::{RandomExt, F32};
///
/// # fn main() {
/// let a = Array::random((2, 5), F32(Normal::new(0., 1.)));
/// println!("{:8.4}", a);
/// // Example Output:
/// // [[ -0.6910,   1.1730,   1.0902,  -0.4092,  -1.7340],
/// //  [ -0.6810,   0.1678,  -0.9487,   0.3150,   1.2981]]
/// # }
#[derive(Copy, Clone, Debug)]
pub struct F32<S>(pub S);

impl<S> Sample<f32> for F32<S>
    where S: Sample<f64>
{
    fn sample<R>(&mut self, rng: &mut R) -> f32 where R: Rng {
        self.0.sample(rng) as f32
    }
}

impl<S> IndependentSample<f32> for F32<S>
    where S: IndependentSample<f64>
{
    fn ind_sample<R>(&self, rng: &mut R) -> f32 where R: Rng {
        self.0.ind_sample(rng) as f32
    }
}
<|endoftext|>