<commit_before>#![cfg(test)]

extern crate esprit;
extern crate estree;
extern crate joker;
extern crate serde_json;

// From 'rustc-test' crate.
// Mirrors Rust's internal 'libtest'.
// https://doc.rust-lang.org/1.1.0/test/index.html
extern crate test;

extern crate unjson;

use esprit::script;
use estree::IntoScript;
use joker::track::Untrack;
use serde_json::value::Value;
use std::ffi::OsStr;
use std::fs::{File, read_dir};
use std::io::Read;
use std::path::Path;
use std::{thread, env};
use test::{TestDesc, TestDescAndFn, TestName, TestFn, Bencher, TDynBenchFn, test_main};
use test::ShouldPanic::No;
use unjson::Unjson;

struct DynBenchFn<F> {
    run: F
}

impl<F: Fn(&mut Bencher) + Send + 'static> TDynBenchFn for DynBenchFn<F> {
    fn run(&self, harness: &mut Bencher) {
        (self.run)(harness);
    }
}

fn add_bench<F: Fn(&mut Bencher) + Send + 'static>(tests: &mut Vec<TestDescAndFn>, name: String, ignore: bool, f: F) {
    tests.push(TestDescAndFn {
        desc: TestDesc {
            name: TestName::DynTestName(name),
            ignore: ignore,
            should_panic: No
        },
        testfn: TestFn::DynBenchFn(Box::new(DynBenchFn { run: f }))
    });
}

fn integration_tests(target: &mut Vec<TestDescAndFn>, ignore: bool, stack_size: usize) {
    let root = Path::new(env!("CARGO_MANIFEST_DIR"));

    let fixtures = {
        let mut fixtures = root.to_path_buf();
        fixtures.push("tests");
        fixtures.push("esprima");
        fixtures.push("test");
        fixtures.push("3rdparty");
        fixtures
    };

    let syntax = fixtures.join("syntax");

    let files =
        read_dir(syntax).unwrap()
        .map(|dir| dir.unwrap().path())
        .filter(|path| path.extension() == Some(OsStr::new("json")))
        .map(|tree_path| {
            let mut source_path = fixtures.join(tree_path.file_name().unwrap());
            source_path.set_extension("js");
            let name = source_path.strip_prefix(&root).unwrap().to_str().unwrap().to_string();

            (tree_path, source_path, name)
        });

    if ignore {
        // Fast path for ignored tests needs only their names
        for (_, _, name) in files {
            add_bench(target, name, true, |_| {});
        }
        return;
    }

    let tests =
        files
        .map(|(tree_path, source_path, name)| {
            let tree_name = tree_path.strip_prefix(&root).unwrap().to_str().unwrap().to_string();

            // Read & parse each JSON in dedicated thread
            let thread =
                thread::Builder::new()
                .name(tree_name.clone())
                .stack_size(stack_size)
                .spawn(move || {
                    let mut source = String::new();
                    File::open(source_path).unwrap().read_to_string(&mut source).unwrap();

                    println!("Parsing JSON {}...", tree_name);
                    let expected_ast = {
                        let v: Value = serde_json::de::from_reader(File::open(&tree_path).unwrap()).unwrap();
                        v.into_object().unwrap().into_script().map_err(|err| {
                            format!("failed to deserialize script: {}", err)
                        }).unwrap()
                    };
                    println!("Done parsing {}", tree_name);
                    (source, expected_ast)
                })
                .unwrap();

            (name, thread)
        })
        // First collect to evaluate iterator and spawn threads
        .collect::<Vec<_>>()
        .into_iter()
        .map(|(name, thread)| {
            let (source, expected_ast) = thread.join().unwrap();
            (name, source, expected_ast)
        })
         // Then collect results from threads so that they don't affect benchmark numbers
        .collect::<Vec<_>>();

    for (name, source, expected_ast) in tests {
        add_bench(target, name, false, move |mut bench| {
            let mut result = None;
            bench.iter(|| {
                result = Some(script(&source[..]))
            });
            match result.unwrap() {
                Ok(mut actual_ast) => {
                    actual_ast.untrack();
                    assert!(actual_ast == expected_ast, "integration test got wrong result");
                }
                Err(actual_err) => {
                    panic!("integration test failed to parse:\n{:#?}", actual_err);
                }
            }
        });
    }
}

fn main() {
    let args: Vec<_> = env::args().collect();
    let bench = args.contains(&"--bench".to_string());
    let ignore_integration_tests = !bench && env::var_os("ESTREE_INTEGRATION_TESTS") == None;
    if ignore_integration_tests {
        println!("note: Run with `ESTREE_INTEGRATION_TESTS=1` to run with integration tests (much slower).");
    }
    let stack_size = std::cmp::max(
        // standard Rust env variable
        env::var("RUST_MIN_STACK")
        .ok()
        .and_then(|s| s.parse().ok())
        .unwrap_or_default(),
        // ...but with custom minimal value
        4 * 1024 * 1024
    );
    thread::Builder::new()
    .name("bench".to_string())
    .stack_size(stack_size)
    .spawn(move || {
        let mut tests = Vec::new();
        integration_tests(&mut tests, ignore_integration_tests, stack_size);
        test_main(&args, tests);
    }).unwrap().join().unwrap();
}
<commit_msg>Remove unnecessary mut<commit_after>#![cfg(test)]

extern crate esprit;
extern crate estree;
extern crate joker;
extern crate serde_json;

// From 'rustc-test' crate.
// Mirrors Rust's internal 'libtest'.
// https://doc.rust-lang.org/1.1.0/test/index.html
extern crate test;

extern crate unjson;

use esprit::script;
use estree::IntoScript;
use joker::track::Untrack;
use serde_json::value::Value;
use std::ffi::OsStr;
use std::fs::{File, read_dir};
use std::io::Read;
use std::path::Path;
use std::{thread, env};
use test::{TestDesc, TestDescAndFn, TestName, TestFn, Bencher, TDynBenchFn, test_main};
use test::ShouldPanic::No;
use unjson::Unjson;

struct DynBenchFn<F> {
    run: F
}

impl<F: Fn(&mut Bencher) + Send + 'static> TDynBenchFn for DynBenchFn<F> {
    fn run(&self, harness: &mut Bencher) {
        (self.run)(harness);
    }
}

fn add_bench<F: Fn(&mut Bencher) + Send + 'static>(tests: &mut Vec<TestDescAndFn>, name: String, ignore: bool, f: F) {
    tests.push(TestDescAndFn {
        desc: TestDesc {
            name: TestName::DynTestName(name),
            ignore: ignore,
            should_panic: No
        },
        testfn: TestFn::DynBenchFn(Box::new(DynBenchFn { run: f }))
    });
}

fn integration_tests(target: &mut Vec<TestDescAndFn>, ignore: bool, stack_size: usize) {
    let root = Path::new(env!("CARGO_MANIFEST_DIR"));

    let fixtures = {
        let mut fixtures = root.to_path_buf();
        fixtures.push("tests");
        fixtures.push("esprima");
        fixtures.push("test");
        fixtures.push("3rdparty");
        fixtures
    };

    let syntax = fixtures.join("syntax");

    let files =
        read_dir(syntax).unwrap()
        .map(|dir| dir.unwrap().path())
        .filter(|path| path.extension() == Some(OsStr::new("json")))
        .map(|tree_path| {
            let mut source_path = fixtures.join(tree_path.file_name().unwrap());
            source_path.set_extension("js");
            let name = source_path.strip_prefix(&root).unwrap().to_str().unwrap().to_string();

            (tree_path, source_path, name)
        });

    if ignore {
        // Fast path for ignored tests needs only their names
        for (_, _, name) in files {
            add_bench(target, name, true, |_| {});
        }
        return;
    }

    let tests =
        files
        .map(|(tree_path, source_path, name)| {
            let tree_name = tree_path.strip_prefix(&root).unwrap().to_str().unwrap().to_string();

            // Read & parse each JSON in dedicated thread
            let thread =
                thread::Builder::new()
                .name(tree_name.clone())
                .stack_size(stack_size)
                .spawn(move || {
                    let mut source = String::new();
                    File::open(source_path).unwrap().read_to_string(&mut source).unwrap();

                    println!("Parsing JSON {}...", tree_name);
                    let expected_ast = {
                        let v: Value = serde_json::de::from_reader(File::open(&tree_path).unwrap()).unwrap();
                        v.into_object().unwrap().into_script().map_err(|err| {
                            format!("failed to deserialize script: {}", err)
                        }).unwrap()
                    };
                    println!("Done parsing {}", tree_name);
                    (source, expected_ast)
                })
                .unwrap();

            (name, thread)
        })
        // First collect to evaluate iterator and spawn threads
        .collect::<Vec<_>>()
        .into_iter()
        .map(|(name, thread)| {
            let (source, expected_ast) = thread.join().unwrap();
            (name, source, expected_ast)
        })
         // Then collect results from threads so that they don't affect benchmark numbers
        .collect::<Vec<_>>();

    for (name, source, expected_ast) in tests {
        add_bench(target, name, false, move |bench| {
            let mut result = None;
            bench.iter(|| {
                result = Some(script(&source[..]))
            });
            match result.unwrap() {
                Ok(mut actual_ast) => {
                    actual_ast.untrack();
                    assert!(actual_ast == expected_ast, "integration test got wrong result");
                }
                Err(actual_err) => {
                    panic!("integration test failed to parse:\n{:#?}", actual_err);
                }
            }
        });
    }
}

fn main() {
    let args: Vec<_> = env::args().collect();
    let bench = args.contains(&"--bench".to_string());
    let ignore_integration_tests = !bench && env::var_os("ESTREE_INTEGRATION_TESTS") == None;
    if ignore_integration_tests {
        println!("note: Run with `ESTREE_INTEGRATION_TESTS=1` to run with integration tests (much slower).");
    }
    let stack_size = std::cmp::max(
        // standard Rust env variable
        env::var("RUST_MIN_STACK")
        .ok()
        .and_then(|s| s.parse().ok())
        .unwrap_or_default(),
        // ...but with custom minimal value
        4 * 1024 * 1024
    );
    thread::Builder::new()
    .name("bench".to_string())
    .stack_size(stack_size)
    .spawn(move || {
        let mut tests = Vec::new();
        integration_tests(&mut tests, ignore_integration_tests, stack_size);
        test_main(&args, tests);
    }).unwrap().join().unwrap();
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fs::File;
use std::ops::Drop;
use std::path::PathBuf;
use std::result::Result as RResult;
use std::sync::Arc;
use std::sync::{RwLock, Mutex};

use fs2::FileExt;

use entry::Entry;
use error::StoreError;

/// The Result Type returned by any interaction with the store that could fail
pub type Result<T> = RResult<T, StoreError>;

/// The Index into the Store
pub type StoreId = PathBuf;

/// This Trait allows you to convert various representations to a single one
/// suitable for usage in the Store
trait IntoStoreId {
    fn into_storeid(self) -> StoreId;
}

impl<'a> IntoStoreId for &'a str {
    fn into_storeid(self) -> StoreId {
        PathBuf::from(self)
    }
}

impl<'a> IntoStoreId for &'a String{
    fn into_storeid(self) -> StoreId {
        PathBuf::from(self)
    }
}

impl IntoStoreId for String{
    fn into_storeid(self) -> StoreId {
        PathBuf::from(self)
    }
}

impl IntoStoreId for PathBuf {
    fn into_storeid(self) -> StoreId {
        self
    }
}

impl<'a> IntoStoreId for &'a PathBuf {
    fn into_storeid(self) -> StoreId {
        self.clone()
    }
}

impl<ISI: IntoStoreId> IntoStoreId for (ISI, ISI) {
    fn into_storeid(self) -> StoreId {
        let (first, second) = self;
        let mut res : StoreId = first.into_storeid();
        res.push(second.into_storeid());
        res
    }
}

#[derive(PartialEq)]
enum StoreEntryPresence {
    Present,
    Borrowed
}

/// A store entry, depending on the option type it is either borrowed currently
/// or not.
struct StoreEntry {
    file: File,
    entry: StoreEntryPresence
}

impl StoreEntry {
    /// The entry is currently borrowed, meaning that some thread is currently
    /// mutating it
    fn is_borrowed(&self) -> bool {
        self.entry == StoreEntryPresence::Borrowed
    }

    /// Flush the entry to disk
    fn set_entry(&mut self, entry: Entry) -> Result<()> {
        unimplemented!()
    }

    /// We borrow the entry
    fn get_entry(&mut self) -> Result<Entry> {
        unimplemented!()
    }

    /// We copy the entry
    fn copy_entry(&mut self) -> Result<Entry> {
        unimplemented!()
    }
}

/// The Store itself, through this object one can interact with IMAG's entries
pub struct Store {
    location: PathBuf,

    /**
     * Internal Path->File cache map
     *
     * Caches the files, so they remain flock()ed
     *
     * Could be optimized for a threadsafe HashMap
     */
    entries: Arc<RwLock<HashMap<StoreId, StoreEntry>>>,
}

impl Store {
    /// Creates the Entry at the given location (inside the entry)
    pub fn create(&self, entry: Entry) -> Result<()> {
        unimplemented!();
    }

    /// Borrow a given Entry. When the `FileLockEntry` is either `update`d or
    /// dropped, the new Entry is written to disk
    pub fn retrieve<'a>(&'a self, id: StoreId) -> Result<FileLockEntry<'a>> {
        unimplemented!();
    }

    /// Return the `FileLockEntry` and write to disk
    pub fn update<'a>(&'a self, entry: FileLockEntry<'a>) -> Result<()> {
        self._update(&entry)
    }

    /// Internal method to write to the filesystem store.
    ///
    /// # Assumptions
    /// This method assumes that entry is dropped _right after_ the call, hence
    /// it is not public.
    fn _update<'a>(&'a self, entry: &FileLockEntry<'a>) -> Result<()> {
        unimplemented!();
    }

    /// Retrieve a copy of a given entry, this cannot be used to mutate
    /// the one on disk
    pub fn retrieve_copy(&self, id: StoreId) -> Result<Entry> {
        unimplemented!();
    }

    /// Delete an entry
    pub fn delete(&self, id: StoreId) -> Result<()> {
        unimplemented!();
    }
}

impl Drop for Store {

    /**
     * Unlock all files on drop
     *
     * TODO: Error message when file cannot be unlocked?
     */
    fn drop(&mut self) {
        self.entries.write().unwrap()
            .iter().map(|f| f.1.file.unlock());
    }

}

/// A struct that allows you to borrow an Entry
pub struct FileLockEntry<'a> {
    store: &'a Store,
    entry: Entry,
    key: StoreId,
}

impl<'a> FileLockEntry<'a, > {
    fn new(store: &'a Store, entry: Entry, key: StoreId) -> FileLockEntry<'a> {
        FileLockEntry {
            store: store,
            entry: entry,
            key: key,
        }
    }
}

impl<'a> ::std::ops::Deref for FileLockEntry<'a> {
    type Target = Entry;

    fn deref(&self) -> &Self::Target {
        &self.entry
    }
}

impl<'a> ::std::ops::DerefMut for FileLockEntry<'a> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.entry
    }
}

impl<'a> Drop for FileLockEntry<'a> {
    fn drop(&mut self) {
        self.store._update(self).unwrap()
    }
}

#[cfg(test)]
mod test {
    use std::path::PathBuf;
    use store::{StoreId, IntoStoreId};

    #[test]
    fn into_storeid_trait() {
        let buf = PathBuf::from("abc/def");

        let test = ("abc", "def");
        assert_eq!(buf, test.into_storeid());

        let test = "abc/def";
        assert_eq!(buf, test.into_storeid());

        let test = String::from("abc/def");
        assert_eq!(buf, test.into_storeid());

        let test = PathBuf::from("abc/def");
        assert_eq!(buf, test.into_storeid());
    }
}

<commit_msg>Remove methods which are not needed anymore<commit_after>use std::collections::HashMap;
use std::fs::File;
use std::ops::Drop;
use std::path::PathBuf;
use std::result::Result as RResult;
use std::sync::Arc;
use std::sync::{RwLock, Mutex};

use fs2::FileExt;

use entry::Entry;
use error::StoreError;

/// The Result Type returned by any interaction with the store that could fail
pub type Result<T> = RResult<T, StoreError>;

/// The Index into the Store
pub type StoreId = PathBuf;

/// This Trait allows you to convert various representations to a single one
/// suitable for usage in the Store
trait IntoStoreId {
    fn into_storeid(self) -> StoreId;
}

impl<'a> IntoStoreId for &'a str {
    fn into_storeid(self) -> StoreId {
        PathBuf::from(self)
    }
}

impl<'a> IntoStoreId for &'a String{
    fn into_storeid(self) -> StoreId {
        PathBuf::from(self)
    }
}

impl IntoStoreId for String{
    fn into_storeid(self) -> StoreId {
        PathBuf::from(self)
    }
}

impl IntoStoreId for PathBuf {
    fn into_storeid(self) -> StoreId {
        self
    }
}

impl<'a> IntoStoreId for &'a PathBuf {
    fn into_storeid(self) -> StoreId {
        self.clone()
    }
}

impl<ISI: IntoStoreId> IntoStoreId for (ISI, ISI) {
    fn into_storeid(self) -> StoreId {
        let (first, second) = self;
        let mut res : StoreId = first.into_storeid();
        res.push(second.into_storeid());
        res
    }
}

#[derive(PartialEq)]
enum StoreEntryPresence {
    Present,
    Borrowed
}

/// A store entry, depending on the option type it is either borrowed currently
/// or not.
struct StoreEntry {
    file: File,
    entry: StoreEntryPresence
}

impl StoreEntry {
    /// The entry is currently borrowed, meaning that some thread is currently
    /// mutating it
    fn is_borrowed(&self) -> bool {
        self.entry == StoreEntryPresence::Borrowed
    }
}

/// The Store itself, through this object one can interact with IMAG's entries
pub struct Store {
    location: PathBuf,

    /**
     * Internal Path->File cache map
     *
     * Caches the files, so they remain flock()ed
     *
     * Could be optimized for a threadsafe HashMap
     */
    entries: Arc<RwLock<HashMap<StoreId, StoreEntry>>>,
}

impl Store {
    /// Creates the Entry at the given location (inside the entry)
    pub fn create(&self, entry: Entry) -> Result<()> {
        unimplemented!();
    }

    /// Borrow a given Entry. When the `FileLockEntry` is either `update`d or
    /// dropped, the new Entry is written to disk
    pub fn retrieve<'a>(&'a self, id: StoreId) -> Result<FileLockEntry<'a>> {
        unimplemented!();
    }

    /// Return the `FileLockEntry` and write to disk
    pub fn update<'a>(&'a self, entry: FileLockEntry<'a>) -> Result<()> {
        self._update(&entry)
    }

    /// Internal method to write to the filesystem store.
    ///
    /// # Assumptions
    /// This method assumes that entry is dropped _right after_ the call, hence
    /// it is not public.
    fn _update<'a>(&'a self, entry: &FileLockEntry<'a>) -> Result<()> {
        unimplemented!();
    }

    /// Retrieve a copy of a given entry, this cannot be used to mutate
    /// the one on disk
    pub fn retrieve_copy(&self, id: StoreId) -> Result<Entry> {
        unimplemented!();
    }

    /// Delete an entry
    pub fn delete(&self, id: StoreId) -> Result<()> {
        unimplemented!();
    }
}

impl Drop for Store {

    /**
     * Unlock all files on drop
     *
     * TODO: Error message when file cannot be unlocked?
     */
    fn drop(&mut self) {
        self.entries.write().unwrap()
            .iter().map(|f| f.1.file.unlock());
    }

}

/// A struct that allows you to borrow an Entry
pub struct FileLockEntry<'a> {
    store: &'a Store,
    entry: Entry,
    key: StoreId,
}

impl<'a> FileLockEntry<'a, > {
    fn new(store: &'a Store, entry: Entry, key: StoreId) -> FileLockEntry<'a> {
        FileLockEntry {
            store: store,
            entry: entry,
            key: key,
        }
    }
}

impl<'a> ::std::ops::Deref for FileLockEntry<'a> {
    type Target = Entry;

    fn deref(&self) -> &Self::Target {
        &self.entry
    }
}

impl<'a> ::std::ops::DerefMut for FileLockEntry<'a> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.entry
    }
}

impl<'a> Drop for FileLockEntry<'a> {
    fn drop(&mut self) {
        self.store._update(self).unwrap()
    }
}

#[cfg(test)]
mod test {
    use std::path::PathBuf;
    use store::{StoreId, IntoStoreId};

    #[test]
    fn into_storeid_trait() {
        let buf = PathBuf::from("abc/def");

        let test = ("abc", "def");
        assert_eq!(buf, test.into_storeid());

        let test = "abc/def";
        assert_eq!(buf, test.into_storeid());

        let test = String::from("abc/def");
        assert_eq!(buf, test.into_storeid());

        let test = PathBuf::from("abc/def");
        assert_eq!(buf, test.into_storeid());
    }
}

<|endoftext|>


<commit_before>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Helper functions for implementing `RngCore` functions.
//!
//! For cross-platform reproducibility, these functions all use Little Endian:
//! least-significant part first. For example, `next_u64_via_u32` takes `u32`
//! values `x, y`, then outputs `(y << 32) | x`. To implement `next_u32`
//! from `next_u64` in little-endian order, one should use `next_u64() as u32`.
//!
//! Byte-swapping (like the std `to_le` functions) is only needed to convert
//! to/from byte sequences, and since its purpose is reproducibility,
//! non-reproducible sources (e.g. `OsRng`) need not bother with it.

use crate::RngCore;
use core::cmp::min;

/// Implement `next_u64` via `next_u32`, little-endian order.
pub fn next_u64_via_u32<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
    // Use LE; we explicitly generate one value before the next.
    let x = u64::from(rng.next_u32());
    let y = u64::from(rng.next_u32());
    (y << 32) | x
}

/// Implement `fill_bytes` via `next_u64` and `next_u32`, little-endian order.
///
/// The fastest way to fill a slice is usually to work as long as possible with
/// integers. That is why this method mostly uses `next_u64`, and only when
/// there are 4 or less bytes remaining at the end of the slice it uses
/// `next_u32` once.
pub fn fill_bytes_via_next<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) {
    let mut left = dest;
    while left.len() >= 8 {
        let (l, r) = { left }.split_at_mut(8);
        left = r;
        let chunk: [u8; 8] = rng.next_u64().to_le_bytes();
        l.copy_from_slice(&chunk);
    }
    let n = left.len();
    if n > 4 {
        let chunk: [u8; 8] = rng.next_u64().to_le_bytes();
        left.copy_from_slice(&chunk[..n]);
    } else if n > 0 {
        let chunk: [u8; 4] = rng.next_u32().to_le_bytes();
        left.copy_from_slice(&chunk[..n]);
    }
}

macro_rules! fill_via_chunks {
    ($src:expr, $dst:expr, $ty:ty, $size:expr) => {{
        debug_assert_eq!(core::mem::size_of::<$ty>(), $size);
        let chunk_size_u8 = min($src.len() * $size, $dst.len());
        let chunk_size = (chunk_size_u8 + $size - 1) / $size;

        for (&n, chunk) in $src.iter().zip($dst.chunks_mut($size)) {
            chunk.copy_from_slice(&n.to_le_bytes()[..chunk.len()]);
        }

        (chunk_size, chunk_size_u8)
    }};
}

/// Implement `fill_bytes` by reading chunks from the output buffer of a block
/// based RNG.
///
/// The return values are `(consumed_u32, filled_u8)`.
///
/// `filled_u8` is the number of filled bytes in `dest`, which may be less than
/// the length of `dest`.
/// `consumed_u32` is the number of words consumed from `src`, which is the same
/// as `filled_u8 / 4` rounded up.
///
/// # Example
/// (from `IsaacRng`)
///
/// ```ignore
/// fn fill_bytes(&mut self, dest: &mut [u8]) {
///     let mut read_len = 0;
///     while read_len < dest.len() {
///         if self.index >= self.rsl.len() {
///             self.isaac();
///         }
///
///         let (consumed_u32, filled_u8) =
///             impls::fill_via_u32_chunks(&mut self.rsl[self.index..],
///                                        &mut dest[read_len..]);
///
///         self.index += consumed_u32;
///         read_len += filled_u8;
///     }
/// }
/// ```
pub fn fill_via_u32_chunks(src: &[u32], dest: &mut [u8]) -> (usize, usize) {
    fill_via_chunks!(src, dest, u32, 4)
}

/// Implement `fill_bytes` by reading chunks from the output buffer of a block
/// based RNG.
///
/// The return values are `(consumed_u64, filled_u8)`.
/// `filled_u8` is the number of filled bytes in `dest`, which may be less than
/// the length of `dest`.
/// `consumed_u64` is the number of words consumed from `src`, which is the same
/// as `filled_u8 / 8` rounded up.
///
/// See `fill_via_u32_chunks` for an example.
pub fn fill_via_u64_chunks(src: &[u64], dest: &mut [u8]) -> (usize, usize) {
    fill_via_chunks!(src, dest, u64, 8)
}

/// Implement `next_u32` via `fill_bytes`, little-endian order.
pub fn next_u32_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u32 {
    let mut buf = [0; 4];
    rng.fill_bytes(&mut buf);
    u32::from_ne_bytes(buf)
}

/// Implement `next_u64` via `fill_bytes`, little-endian order.
pub fn next_u64_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
    let mut buf = [0; 8];
    rng.fill_bytes(&mut buf);
    u64::from_ne_bytes(buf)
}

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

    #[test]
    fn test_fill_via_u32_chunks() {
        let src = [1, 2, 3];
        let mut dst = [0u8; 11];
        assert_eq!(fill_via_u32_chunks(&src, &mut dst), (3, 11));
        assert_eq!(dst, [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0]);

        let mut dst = [0u8; 13];
        assert_eq!(fill_via_u32_chunks(&src, &mut dst), (3, 12));
        assert_eq!(dst, [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0]);

        let mut dst = [0u8; 5];
        assert_eq!(fill_via_u32_chunks(&src, &mut dst), (2, 5));
        assert_eq!(dst, [1, 0, 0, 0, 2]);
    }

    #[test]
    fn test_fill_via_u64_chunks() {
        let src = [1, 2];
        let mut dst = [0u8; 11];
        assert_eq!(fill_via_u64_chunks(&src, &mut dst), (2, 11));
        assert_eq!(dst, [1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0]);

        let mut dst = [0u8; 17];
        assert_eq!(fill_via_u64_chunks(&src, &mut dst), (2, 16));
        assert_eq!(dst, [1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0]);

        let mut dst = [0u8; 5];
        assert_eq!(fill_via_u64_chunks(&src, &mut dst), (1, 5));
        assert_eq!(dst, [1, 0, 0, 0, 0]);
    }
}
<commit_msg>Simplify macro<commit_after>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Helper functions for implementing `RngCore` functions.
//!
//! For cross-platform reproducibility, these functions all use Little Endian:
//! least-significant part first. For example, `next_u64_via_u32` takes `u32`
//! values `x, y`, then outputs `(y << 32) | x`. To implement `next_u32`
//! from `next_u64` in little-endian order, one should use `next_u64() as u32`.
//!
//! Byte-swapping (like the std `to_le` functions) is only needed to convert
//! to/from byte sequences, and since its purpose is reproducibility,
//! non-reproducible sources (e.g. `OsRng`) need not bother with it.

use crate::RngCore;
use core::cmp::min;

/// Implement `next_u64` via `next_u32`, little-endian order.
pub fn next_u64_via_u32<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
    // Use LE; we explicitly generate one value before the next.
    let x = u64::from(rng.next_u32());
    let y = u64::from(rng.next_u32());
    (y << 32) | x
}

/// Implement `fill_bytes` via `next_u64` and `next_u32`, little-endian order.
///
/// The fastest way to fill a slice is usually to work as long as possible with
/// integers. That is why this method mostly uses `next_u64`, and only when
/// there are 4 or less bytes remaining at the end of the slice it uses
/// `next_u32` once.
pub fn fill_bytes_via_next<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) {
    let mut left = dest;
    while left.len() >= 8 {
        let (l, r) = { left }.split_at_mut(8);
        left = r;
        let chunk: [u8; 8] = rng.next_u64().to_le_bytes();
        l.copy_from_slice(&chunk);
    }
    let n = left.len();
    if n > 4 {
        let chunk: [u8; 8] = rng.next_u64().to_le_bytes();
        left.copy_from_slice(&chunk[..n]);
    } else if n > 0 {
        let chunk: [u8; 4] = rng.next_u32().to_le_bytes();
        left.copy_from_slice(&chunk[..n]);
    }
}

macro_rules! fill_via_chunks {
    ($src:expr, $dst:expr, $ty:ty) => {{
        const SIZE: usize = core::mem::size_of::<$ty>();
        let chunk_size_u8 = min($src.len() * SIZE, $dst.len());
        let chunk_size = (chunk_size_u8 + SIZE - 1) / SIZE;

        for (&n, chunk) in $src.iter().zip($dst.chunks_mut(SIZE)) {
            chunk.copy_from_slice(&n.to_le_bytes()[..chunk.len()]);
        }

        (chunk_size, chunk_size_u8)
    }};
}

/// Implement `fill_bytes` by reading chunks from the output buffer of a block
/// based RNG.
///
/// The return values are `(consumed_u32, filled_u8)`.
///
/// `filled_u8` is the number of filled bytes in `dest`, which may be less than
/// the length of `dest`.
/// `consumed_u32` is the number of words consumed from `src`, which is the same
/// as `filled_u8 / 4` rounded up.
///
/// # Example
/// (from `IsaacRng`)
///
/// ```ignore
/// fn fill_bytes(&mut self, dest: &mut [u8]) {
///     let mut read_len = 0;
///     while read_len < dest.len() {
///         if self.index >= self.rsl.len() {
///             self.isaac();
///         }
///
///         let (consumed_u32, filled_u8) =
///             impls::fill_via_u32_chunks(&mut self.rsl[self.index..],
///                                        &mut dest[read_len..]);
///
///         self.index += consumed_u32;
///         read_len += filled_u8;
///     }
/// }
/// ```
pub fn fill_via_u32_chunks(src: &[u32], dest: &mut [u8]) -> (usize, usize) {
    fill_via_chunks!(src, dest, u32)
}

/// Implement `fill_bytes` by reading chunks from the output buffer of a block
/// based RNG.
///
/// The return values are `(consumed_u64, filled_u8)`.
/// `filled_u8` is the number of filled bytes in `dest`, which may be less than
/// the length of `dest`.
/// `consumed_u64` is the number of words consumed from `src`, which is the same
/// as `filled_u8 / 8` rounded up.
///
/// See `fill_via_u32_chunks` for an example.
pub fn fill_via_u64_chunks(src: &[u64], dest: &mut [u8]) -> (usize, usize) {
    fill_via_chunks!(src, dest, u64)
}

/// Implement `next_u32` via `fill_bytes`, little-endian order.
pub fn next_u32_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u32 {
    let mut buf = [0; 4];
    rng.fill_bytes(&mut buf);
    u32::from_ne_bytes(buf)
}

/// Implement `next_u64` via `fill_bytes`, little-endian order.
pub fn next_u64_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
    let mut buf = [0; 8];
    rng.fill_bytes(&mut buf);
    u64::from_ne_bytes(buf)
}

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

    #[test]
    fn test_fill_via_u32_chunks() {
        let src = [1, 2, 3];
        let mut dst = [0u8; 11];
        assert_eq!(fill_via_u32_chunks(&src, &mut dst), (3, 11));
        assert_eq!(dst, [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0]);

        let mut dst = [0u8; 13];
        assert_eq!(fill_via_u32_chunks(&src, &mut dst), (3, 12));
        assert_eq!(dst, [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0]);

        let mut dst = [0u8; 5];
        assert_eq!(fill_via_u32_chunks(&src, &mut dst), (2, 5));
        assert_eq!(dst, [1, 0, 0, 0, 2]);
    }

    #[test]
    fn test_fill_via_u64_chunks() {
        let src = [1, 2];
        let mut dst = [0u8; 11];
        assert_eq!(fill_via_u64_chunks(&src, &mut dst), (2, 11));
        assert_eq!(dst, [1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0]);

        let mut dst = [0u8; 17];
        assert_eq!(fill_via_u64_chunks(&src, &mut dst), (2, 16));
        assert_eq!(dst, [1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0]);

        let mut dst = [0u8; 5];
        assert_eq!(fill_via_u64_chunks(&src, &mut dst), (1, 5));
        assert_eq!(dst, [1, 0, 0, 0, 0]);
    }
}
<|endoftext|>


<commit_before>//! Checks for uses of const which the type is not `Freeze` (`Cell`-free).
//!
//! This lint is **deny** by default.

use std::ptr;

use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp};
use rustc_lint::{LateContext, LateLintPass, Lint};
use rustc_middle::ty::adjustment::Adjust;
use rustc_middle::ty::{Ty, TypeFlags};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{InnerSpan, Span, DUMMY_SP};
use rustc_typeck::hir_ty_to_ty;

use crate::utils::{in_constant, is_copy, qpath_res, span_lint_and_then};

declare_clippy_lint! {
    /// **What it does:** Checks for declaration of `const` items which is interior
    /// mutable (e.g., contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.).
    ///
    /// **Why is this bad?** Consts are copied everywhere they are referenced, i.e.,
    /// every time you refer to the const a fresh instance of the `Cell` or `Mutex`
    /// or `AtomicXxxx` will be created, which defeats the whole purpose of using
    /// these types in the first place.
    ///
    /// The `const` should better be replaced by a `static` item if a global
    /// variable is wanted, or replaced by a `const fn` if a constructor is wanted.
    ///
    /// **Known problems:** A "non-constant" const item is a legacy way to supply an
    /// initialized value to downstream `static` items (e.g., the
    /// `std::sync::ONCE_INIT` constant). In this case the use of `const` is legit,
    /// and this lint should be suppressed.
    ///
    /// **Example:**
    /// ```rust
    /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
    ///
    /// // Bad.
    /// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
    /// CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged
    /// assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct
    ///
    /// // Good.
    /// static STATIC_ATOM: AtomicUsize = AtomicUsize::new(15);
    /// STATIC_ATOM.store(9, SeqCst);
    /// assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance
    /// ```
    pub DECLARE_INTERIOR_MUTABLE_CONST,
    correctness,
    "declaring `const` with interior mutability"
}

declare_clippy_lint! {
    /// **What it does:** Checks if `const` items which is interior mutable (e.g.,
    /// contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.) has been borrowed directly.
    ///
    /// **Why is this bad?** Consts are copied everywhere they are referenced, i.e.,
    /// every time you refer to the const a fresh instance of the `Cell` or `Mutex`
    /// or `AtomicXxxx` will be created, which defeats the whole purpose of using
    /// these types in the first place.
    ///
    /// The `const` value should be stored inside a `static` item.
    ///
    /// **Known problems:** None
    ///
    /// **Example:**
    /// ```rust
    /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
    /// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
    ///
    /// // Bad.
    /// CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged
    /// assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct
    ///
    /// // Good.
    /// static STATIC_ATOM: AtomicUsize = CONST_ATOM;
    /// STATIC_ATOM.store(9, SeqCst);
    /// assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance
    /// ```
    pub BORROW_INTERIOR_MUTABLE_CONST,
    correctness,
    "referencing `const` with interior mutability"
}

#[allow(dead_code)]
#[derive(Copy, Clone)]
enum Source {
    Item { item: Span },
    Assoc { item: Span, ty: Span },
    Expr { expr: Span },
}

impl Source {
    #[must_use]
    fn lint(&self) -> (&'static Lint, &'static str, Span) {
        match self {
            Self::Item { item } | Self::Assoc { item, .. } => (
                DECLARE_INTERIOR_MUTABLE_CONST,
                "a `const` item should never be interior mutable",
                *item,
            ),
            Self::Expr { expr } => (
                BORROW_INTERIOR_MUTABLE_CONST,
                "a `const` item with interior mutability should not be borrowed",
                *expr,
            ),
        }
    }
}

fn verify_ty_bound<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, source: Source) {
    if ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env) || is_copy(cx, ty) {
        // An `UnsafeCell` is `!Copy`, and an `UnsafeCell` is also the only type which
        // is `!Freeze`, thus if our type is `Copy` we can be sure it must be `Freeze`
        // as well.
        return;
    }

    let (lint, msg, span) = source.lint();
    span_lint_and_then(cx, lint, span, msg, |diag| {
        if span.from_expansion() {
            return; // Don't give suggestions into macros.
        }
        match source {
            Source::Item { .. } => {
                let const_kw_span = span.from_inner(InnerSpan::new(0, 5));
                diag.span_label(const_kw_span, "make this a static item (maybe with lazy_static)");
            },
            Source::Assoc { ty: ty_span, .. } => {
                if ty.flags.intersects(TypeFlags::HAS_FREE_LOCAL_NAMES) {
                    diag.span_label(ty_span, &format!("consider requiring `{}` to be `Copy`", ty));
                }
            },
            Source::Expr { .. } => {
                diag.help("assign this const to a local or static variable, and use the variable here");
            },
        }
    });
}

declare_lint_pass!(NonCopyConst => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]);

impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
    fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) {
        if let ItemKind::Const(hir_ty, ..) = &it.kind {
            let ty = hir_ty_to_ty(cx.tcx, hir_ty);
            verify_ty_bound(cx, ty, Source::Item { item: it.span });
        }
    }

    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'_>) {
        if let TraitItemKind::Const(hir_ty, ..) = &trait_item.kind {
            let ty = hir_ty_to_ty(cx.tcx, hir_ty);
            verify_ty_bound(
                cx,
                ty,
                Source::Assoc {
                    ty: hir_ty.span,
                    item: trait_item.span,
                },
            );
        }
    }

    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
        if let ImplItemKind::Const(hir_ty, ..) = &impl_item.kind {
            let item_hir_id = cx.tcx.hir().get_parent_node(impl_item.hir_id);
            let item = cx.tcx.hir().expect_item(item_hir_id);
            // Ensure the impl is an inherent impl.
            if let ItemKind::Impl { of_trait: None, .. } = item.kind {
                let ty = hir_ty_to_ty(cx.tcx, hir_ty);
                verify_ty_bound(
                    cx,
                    ty,
                    Source::Assoc {
                        ty: hir_ty.span,
                        item: impl_item.span,
                    },
                );
            }
        }
    }

    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        if let ExprKind::Path(qpath) = &expr.kind {
            // Only lint if we use the const item inside a function.
            if in_constant(cx, expr.hir_id) {
                return;
            }

            // Make sure it is a const item.
            match qpath_res(cx, qpath, expr.hir_id) {
                Res::Def(DefKind::Const | DefKind::AssocConst, _) => {},
                _ => return,
            };

            // Climb up to resolve any field access and explicit referencing.
            let mut cur_expr = expr;
            let mut dereferenced_expr = expr;
            let mut needs_check_adjustment = true;
            loop {
                let parent_id = cx.tcx.hir().get_parent_node(cur_expr.hir_id);
                if parent_id == cur_expr.hir_id {
                    break;
                }
                if let Some(Node::Expr(parent_expr)) = cx.tcx.hir().find(parent_id) {
                    match &parent_expr.kind {
                        ExprKind::AddrOf(..) => {
                            // `&e` => `e` must be referenced.
                            needs_check_adjustment = false;
                        },
                        ExprKind::Field(..) => {
                            needs_check_adjustment = true;

                            // Check whether implicit dereferences happened;
                            // if so, no need to go further up
                            // because of the same reason as the `ExprKind::Unary` case.
                            if cx
                                .typeck_results()
                                .expr_adjustments(dereferenced_expr)
                                .iter()
                                .any(|adj| matches!(adj.kind, Adjust::Deref(_)))
                            {
                                break;
                            }

                            dereferenced_expr = parent_expr;
                        },
                        ExprKind::Index(e, _) if ptr::eq(&**e, cur_expr) => {
                            // `e[i]` => desugared to `*Index::index(&e, i)`,
                            // meaning `e` must be referenced.
                            // no need to go further up since a method call is involved now.
                            needs_check_adjustment = false;
                            break;
                        },
                        ExprKind::Unary(UnOp::UnDeref, _) => {
                            // `*e` => desugared to `*Deref::deref(&e)`,
                            // meaning `e` must be referenced.
                            // no need to go further up since a method call is involved now.
                            needs_check_adjustment = false;
                            break;
                        },
                        _ => break,
                    }
                    cur_expr = parent_expr;
                } else {
                    break;
                }
            }

            let ty = if needs_check_adjustment {
                let adjustments = cx.typeck_results().expr_adjustments(dereferenced_expr);
                if let Some(i) = adjustments
                    .iter()
                    .position(|adj| matches!(adj.kind, Adjust::Borrow(_) | Adjust::Deref(_)))
                {
                    if i == 0 {
                        cx.typeck_results().expr_ty(dereferenced_expr)
                    } else {
                        adjustments[i - 1].target
                    }
                } else {
                    // No borrow adjustments means the entire const is moved.
                    return;
                }
            } else {
                cx.typeck_results().expr_ty(dereferenced_expr)
            };

            verify_ty_bound(cx, ty, Source::Expr { expr: expr.span });
        }
    }
}
<commit_msg>ty.flags -> ty.flags()<commit_after>//! Checks for uses of const which the type is not `Freeze` (`Cell`-free).
//!
//! This lint is **deny** by default.

use std::ptr;

use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp};
use rustc_lint::{LateContext, LateLintPass, Lint};
use rustc_middle::ty::adjustment::Adjust;
use rustc_middle::ty::{Ty, TypeFlags};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{InnerSpan, Span, DUMMY_SP};
use rustc_typeck::hir_ty_to_ty;

use crate::utils::{in_constant, is_copy, qpath_res, span_lint_and_then};

declare_clippy_lint! {
    /// **What it does:** Checks for declaration of `const` items which is interior
    /// mutable (e.g., contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.).
    ///
    /// **Why is this bad?** Consts are copied everywhere they are referenced, i.e.,
    /// every time you refer to the const a fresh instance of the `Cell` or `Mutex`
    /// or `AtomicXxxx` will be created, which defeats the whole purpose of using
    /// these types in the first place.
    ///
    /// The `const` should better be replaced by a `static` item if a global
    /// variable is wanted, or replaced by a `const fn` if a constructor is wanted.
    ///
    /// **Known problems:** A "non-constant" const item is a legacy way to supply an
    /// initialized value to downstream `static` items (e.g., the
    /// `std::sync::ONCE_INIT` constant). In this case the use of `const` is legit,
    /// and this lint should be suppressed.
    ///
    /// **Example:**
    /// ```rust
    /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
    ///
    /// // Bad.
    /// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
    /// CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged
    /// assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct
    ///
    /// // Good.
    /// static STATIC_ATOM: AtomicUsize = AtomicUsize::new(15);
    /// STATIC_ATOM.store(9, SeqCst);
    /// assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance
    /// ```
    pub DECLARE_INTERIOR_MUTABLE_CONST,
    correctness,
    "declaring `const` with interior mutability"
}

declare_clippy_lint! {
    /// **What it does:** Checks if `const` items which is interior mutable (e.g.,
    /// contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.) has been borrowed directly.
    ///
    /// **Why is this bad?** Consts are copied everywhere they are referenced, i.e.,
    /// every time you refer to the const a fresh instance of the `Cell` or `Mutex`
    /// or `AtomicXxxx` will be created, which defeats the whole purpose of using
    /// these types in the first place.
    ///
    /// The `const` value should be stored inside a `static` item.
    ///
    /// **Known problems:** None
    ///
    /// **Example:**
    /// ```rust
    /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
    /// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
    ///
    /// // Bad.
    /// CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged
    /// assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct
    ///
    /// // Good.
    /// static STATIC_ATOM: AtomicUsize = CONST_ATOM;
    /// STATIC_ATOM.store(9, SeqCst);
    /// assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance
    /// ```
    pub BORROW_INTERIOR_MUTABLE_CONST,
    correctness,
    "referencing `const` with interior mutability"
}

#[allow(dead_code)]
#[derive(Copy, Clone)]
enum Source {
    Item { item: Span },
    Assoc { item: Span, ty: Span },
    Expr { expr: Span },
}

impl Source {
    #[must_use]
    fn lint(&self) -> (&'static Lint, &'static str, Span) {
        match self {
            Self::Item { item } | Self::Assoc { item, .. } => (
                DECLARE_INTERIOR_MUTABLE_CONST,
                "a `const` item should never be interior mutable",
                *item,
            ),
            Self::Expr { expr } => (
                BORROW_INTERIOR_MUTABLE_CONST,
                "a `const` item with interior mutability should not be borrowed",
                *expr,
            ),
        }
    }
}

fn verify_ty_bound<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, source: Source) {
    if ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env) || is_copy(cx, ty) {
        // An `UnsafeCell` is `!Copy`, and an `UnsafeCell` is also the only type which
        // is `!Freeze`, thus if our type is `Copy` we can be sure it must be `Freeze`
        // as well.
        return;
    }

    let (lint, msg, span) = source.lint();
    span_lint_and_then(cx, lint, span, msg, |diag| {
        if span.from_expansion() {
            return; // Don't give suggestions into macros.
        }
        match source {
            Source::Item { .. } => {
                let const_kw_span = span.from_inner(InnerSpan::new(0, 5));
                diag.span_label(const_kw_span, "make this a static item (maybe with lazy_static)");
            },
            Source::Assoc { ty: ty_span, .. } => {
                if ty.flags().intersects(TypeFlags::HAS_FREE_LOCAL_NAMES) {
                    diag.span_label(ty_span, &format!("consider requiring `{}` to be `Copy`", ty));
                }
            },
            Source::Expr { .. } => {
                diag.help("assign this const to a local or static variable, and use the variable here");
            },
        }
    });
}

declare_lint_pass!(NonCopyConst => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]);

impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
    fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) {
        if let ItemKind::Const(hir_ty, ..) = &it.kind {
            let ty = hir_ty_to_ty(cx.tcx, hir_ty);
            verify_ty_bound(cx, ty, Source::Item { item: it.span });
        }
    }

    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'_>) {
        if let TraitItemKind::Const(hir_ty, ..) = &trait_item.kind {
            let ty = hir_ty_to_ty(cx.tcx, hir_ty);
            verify_ty_bound(
                cx,
                ty,
                Source::Assoc {
                    ty: hir_ty.span,
                    item: trait_item.span,
                },
            );
        }
    }

    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
        if let ImplItemKind::Const(hir_ty, ..) = &impl_item.kind {
            let item_hir_id = cx.tcx.hir().get_parent_node(impl_item.hir_id);
            let item = cx.tcx.hir().expect_item(item_hir_id);
            // Ensure the impl is an inherent impl.
            if let ItemKind::Impl { of_trait: None, .. } = item.kind {
                let ty = hir_ty_to_ty(cx.tcx, hir_ty);
                verify_ty_bound(
                    cx,
                    ty,
                    Source::Assoc {
                        ty: hir_ty.span,
                        item: impl_item.span,
                    },
                );
            }
        }
    }

    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        if let ExprKind::Path(qpath) = &expr.kind {
            // Only lint if we use the const item inside a function.
            if in_constant(cx, expr.hir_id) {
                return;
            }

            // Make sure it is a const item.
            match qpath_res(cx, qpath, expr.hir_id) {
                Res::Def(DefKind::Const | DefKind::AssocConst, _) => {},
                _ => return,
            };

            // Climb up to resolve any field access and explicit referencing.
            let mut cur_expr = expr;
            let mut dereferenced_expr = expr;
            let mut needs_check_adjustment = true;
            loop {
                let parent_id = cx.tcx.hir().get_parent_node(cur_expr.hir_id);
                if parent_id == cur_expr.hir_id {
                    break;
                }
                if let Some(Node::Expr(parent_expr)) = cx.tcx.hir().find(parent_id) {
                    match &parent_expr.kind {
                        ExprKind::AddrOf(..) => {
                            // `&e` => `e` must be referenced.
                            needs_check_adjustment = false;
                        },
                        ExprKind::Field(..) => {
                            needs_check_adjustment = true;

                            // Check whether implicit dereferences happened;
                            // if so, no need to go further up
                            // because of the same reason as the `ExprKind::Unary` case.
                            if cx
                                .typeck_results()
                                .expr_adjustments(dereferenced_expr)
                                .iter()
                                .any(|adj| matches!(adj.kind, Adjust::Deref(_)))
                            {
                                break;
                            }

                            dereferenced_expr = parent_expr;
                        },
                        ExprKind::Index(e, _) if ptr::eq(&**e, cur_expr) => {
                            // `e[i]` => desugared to `*Index::index(&e, i)`,
                            // meaning `e` must be referenced.
                            // no need to go further up since a method call is involved now.
                            needs_check_adjustment = false;
                            break;
                        },
                        ExprKind::Unary(UnOp::UnDeref, _) => {
                            // `*e` => desugared to `*Deref::deref(&e)`,
                            // meaning `e` must be referenced.
                            // no need to go further up since a method call is involved now.
                            needs_check_adjustment = false;
                            break;
                        },
                        _ => break,
                    }
                    cur_expr = parent_expr;
                } else {
                    break;
                }
            }

            let ty = if needs_check_adjustment {
                let adjustments = cx.typeck_results().expr_adjustments(dereferenced_expr);
                if let Some(i) = adjustments
                    .iter()
                    .position(|adj| matches!(adj.kind, Adjust::Borrow(_) | Adjust::Deref(_)))
                {
                    if i == 0 {
                        cx.typeck_results().expr_ty(dereferenced_expr)
                    } else {
                        adjustments[i - 1].target
                    }
                } else {
                    // No borrow adjustments means the entire const is moved.
                    return;
                }
            } else {
                cx.typeck_results().expr_ty(dereferenced_expr)
            };

            verify_ty_bound(cx, ty, Source::Expr { expr: expr.span });
        }
    }
}
<|endoftext|>


<commit_before>use libc::*;
use std::mem::transmute;
use std::slice;
use std::str;
use CFixedString;

#[repr(C)]
pub struct CPDReaderAPI {
    pub data: *mut c_void,
    pub read_get_event: extern fn(reader: *mut c_void) -> uint32_t,
    pub read_iterator_next_event: extern fn(reader: *mut c_void,
                                            it: *mut uint64_t) -> uint32_t,
    pub read_iterator_begin: extern fn(reader: *mut c_void, it: *mut uint64_t,
                                       keyName: *mut *const c_char, parentIt: uint64_t)
                                    -> uint32_t,
    pub read_iterator_next: extern fn(reader: *mut c_void, keyName: *mut *const c_char,
                                      it: *mut uint64_t) -> uint32_t,
    pub read_next_entry: extern fn(reader: *mut c_void, arrayIt: *mut uint64_t)
                                -> int32_t,
    pub read_find_s8: extern fn(reader: *mut c_void, res: *mut int8_t, id: *const c_char,
                                it: uint64_t) -> uint32_t,
    pub read_find_u8: extern fn(reader: *mut c_void, res: *mut uint8_t, id: *const c_char,
                                it: uint64_t) -> uint32_t,
    pub read_find_s16: extern fn(reader: *mut c_void, res: *mut int16_t, id: *const c_char,
                                 it: uint64_t) -> uint32_t,
    pub read_find_u16: extern fn(reader: *mut c_void, res: *mut uint16_t, id: *const c_char,
                                 it: uint64_t) -> uint32_t,
    pub read_find_s32: extern fn(reader: *mut c_void, res: *mut int32_t, id: *const c_char,
                                 it: uint64_t) -> uint32_t,
    pub read_find_u32: extern fn(reader: *mut c_void, res: *mut uint32_t, id: *const c_char,
                                 it: uint64_t) -> uint32_t,
    pub read_find_s64: extern fn(reader: *mut c_void, res: *mut int64_t, id: *const c_char,
                                 it: uint64_t) -> uint32_t,
    pub read_find_u64: extern fn(reader: *mut c_void, res: *mut uint64_t, id: *const c_char,
                                 it: uint64_t) -> uint32_t,
    pub read_find_float: extern fn(reader: *mut c_void, res: *mut c_float, id: *const c_char,
                                   it: uint64_t) -> uint32_t,
    pub read_find_double: extern fn(reader: *mut c_void, res: *mut c_double, id: *const c_char,
                                    it: uint64_t) -> uint32_t,
    pub read_find_string: extern fn(reader: *mut c_void, res: *mut *const c_char, id: *const c_char,
                                    it: uint64_t) -> uint32_t,
    pub read_find_data: extern fn(reader: *mut c_void, data: *mut *mut c_void, size: *mut uint64_t,
                                  id: *const c_char, it: uint64_t) -> uint32_t,
    pub read_find_array: extern fn(reader: *mut c_void, arrayIt: *mut uint64_t, id: *const c_char,
                                   it: uint64_t) -> uint32_t,
    pub read_dump_data: extern fn(reader: *mut c_void),
}

#[repr(C)]
pub enum WriteStatus {
    Ok,
    Fail,
}

#[repr(C)]
pub struct CPDWriterAPI {
    private_data: *mut c_void,
    pub write_event_begin: extern "C" fn(writer: *mut c_void, event: uint16_t) -> WriteStatus,
    pub write_event_end: extern fn(writer: *mut c_void) -> WriteStatus,
    pub write_header_array_begin: extern fn(writer: *mut c_void, ids: *mut *const c_char)
                                         -> WriteStatus,
    pub write_header_array_end: extern fn(writer: *mut c_void) -> WriteStatus,
    pub write_array_begin: extern fn(writer: *mut c_void, name: *const c_char) -> WriteStatus,
    pub write_array_end: extern fn(writer: *mut c_void) -> WriteStatus,
    pub write_array_entry_begin: extern fn(writer: *mut c_void) -> WriteStatus,
    pub write_array_entry_end: extern fn(writer: *mut c_void) -> WriteStatus,
    pub write_s8: extern fn(writer: *mut c_void, id: *const c_char, v: int8_t) -> WriteStatus,
    pub write_u8: extern fn(writer: *mut c_void, id: *const c_char, v: uint8_t) -> WriteStatus,
    pub write_s16: extern fn(writer: *mut c_void, id: *const c_char, v: int16_t) -> WriteStatus,
    pub write_u16: extern fn(writer: *mut c_void, id: *const c_char, v: uint16_t) -> WriteStatus,
    pub write_s32: extern fn(writer: *mut c_void, id: *const c_char, v: int32_t) -> WriteStatus,
    pub write_u32: extern fn(writer: *mut c_void, id: *const c_char, v: uint32_t) -> WriteStatus,
    pub write_s64: extern fn(writer: *mut c_void, id: *const c_char, v: int64_t) -> WriteStatus,
    pub write_u64: extern fn(writer: *mut c_void, id: *const c_char, v: uint64_t) -> WriteStatus,
    pub write_float: extern fn(writer: *mut c_void, id: *const c_char, v: c_float) -> WriteStatus,
    pub write_double: extern fn(writer: *mut c_void, id: *const c_char, v: c_double) -> WriteStatus,
    pub write_string: extern fn(writer: *mut c_void, id: *const c_char, v: *const c_char)
                             -> WriteStatus,
    pub write_data: extern fn(w: *mut c_void, id: *const c_char, d: *const uint8_t, l: c_uint)
                            -> WriteStatus,
}

pub struct Reader {
    pub api: *mut CPDReaderAPI,
    pub it: u64,
}

pub struct Writer {
    pub api: *mut CPDWriterAPI,
}

#[repr(C)]
pub enum ReadType {
    None,
    S8,
    U8,
    S16,
    U16,
    S32,
    U32,
    S64,
    U64,
    Float,
    Double,
    EndNumericTypes,
    Str,
    Data,
    Event,
    Array,
    ArrayEntry,
    Count,
}

#[repr(C)]
pub enum ReadStatus {
    Ok = 1 << 8,
    Converted = 2 << 8,
    IllegalType = 3 << 8,
    NotFound = 4 << 8,
    Fail = 5 << 8,
    TypeMask = 0xff,
}

pub struct ReaderIter {
    reader: Reader,
    curr_iter: u64,
}

pub struct EventIter {
    reader: Reader,
}

impl Clone for Reader {
    fn clone(&self) -> Self {
        return Reader {
            api: self.api,
            it: self.it,
        };
    }
}

fn status_res<T>(res: T, s: u32) -> Result<T, ReadStatus> {
    match (s >> 8) & 0xff {
        1...2 => Ok(res),
        3 => Err(ReadStatus::IllegalType),
        _ => Err(ReadStatus::NotFound),
    }
}

macro_rules! find_fun {
    ($c_name:ident, $name:ident, $data_type:ident) => {
        pub fn $name(&self, id: &str) -> Result<$data_type, ReadStatus> {
            let s = CFixedString::from_str(id).as_ptr();
            let mut res = 0 as $data_type;
            let ret;

            unsafe {
                ret = ((*self.api).$c_name)(transmute(self.api), &mut res, s, self.it);
            }

            return status_res(res, ret);
        }
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

impl Reader {
    pub fn new(in_api: *mut CPDReaderAPI, iter: u64) -> Self {
        return Reader {
            api: in_api,
            it: iter,
        };
    }

    pub fn get_events(&self) -> EventIter {
        EventIter {
            reader: self.clone(),
        }
    }

    pub fn get_event(&self) -> Option<i32> {
        let event_id = unsafe {
            ((*self.api).read_get_event)(transmute(self.api)) as i32
        };

        match event_id {
            0 => None,
            e => Some(e),
        }
    }

    find_fun!(read_find_s8, find_s8, i8);
    find_fun!(read_find_u8, find_u8, u8);
    find_fun!(read_find_s16, find_s16, i16);
    find_fun!(read_find_u16, find_u16, u16);
    find_fun!(read_find_s32, find_s32, i32);
    find_fun!(read_find_u32, find_u32, u32);
    find_fun!(read_find_s64, find_s64, i64);
    find_fun!(read_find_u64, find_u64, u64);
    find_fun!(read_find_float, find_float, f32);
    find_fun!(read_find_double, find_double, f64);

    unsafe fn strlen(t: *const i8) -> usize{
        // very lange slice so this is kinda hacky but should work
        let slice = slice::from_raw_parts(t, 16834);
        let mut count = 0;

        loop {
            if slice[count] == 0 { break; }
            count += 1;
        }

        count
    }

    pub fn find_string(&self, id: &str) -> Result<&str, ReadStatus> {
        let s = CFixedString::from_str(id).as_ptr();
        let mut temp = 0 as *const c_char;
        let ret;
        let res;

        unsafe {
            ret = ((*self.api).read_find_string)(transmute(self.api), &mut temp, s, self.it);
            let slice = slice::from_raw_parts(temp as *const u8, Self::strlen(temp));
            res = str::from_utf8(slice).unwrap();
        }

        return status_res(res, ret);
    }

    pub fn find_array(&self, id: &str) -> ReaderIter {
        let s = CFixedString::from_str(id).as_ptr();
        let mut t = 0u64;

        unsafe {
            ((*self.api).read_find_array)(transmute(self.api), &mut t, s, 0);
        }

        ReaderIter {
            reader: self.clone(),
            curr_iter: t,
        }
    }
}

impl Iterator for ReaderIter {
    type Item = Reader;
    fn next(&mut self) -> Option<Reader> {
        let ret;
        unsafe {
            ret = ((*self.reader.api).read_next_entry)(transmute(self.reader.api),
                                                       &mut self.curr_iter);
        }

        match ret {
            0 => None,
            _ => Some(Reader::new(self.reader.api, self.curr_iter)),
        }
    }
}

impl Iterator for EventIter {
    type Item = i32;
    fn next(&mut self) -> Option<i32> {
        self.reader.get_event()
    }
}

macro_rules! write_fun {
    ($name:ident, $data_type:ident) => {
        pub fn $name(&mut self, id: &str, v: $data_type) {
            let s = CFixedString::from_str(id).as_ptr();
            unsafe {
                ((*self.api).$name)(transmute(self.api), s, v);
            }
        }
    }
}

impl Writer {
    pub fn event_begin(&mut self, event: u16) {
        unsafe {
            ((*self.api).write_event_begin)(transmute(self.api), event);
        }
    }

    pub fn event_end(&mut self) {
        unsafe {
            ((*self.api).write_event_end)(transmute(self.api));
        }
    }

    pub fn array_begin(&mut self, name: &str) {
        let s = CFixedString::from_str(name).as_ptr();
        unsafe {
            ((*self.api).write_array_begin)(transmute(self.api), s);
        }
    }

    pub fn array_end(&mut self) {
        unsafe {
            ((*self.api).write_array_end)(transmute(self.api));
        }
    }

    pub fn array_entry_begin(&mut self) {
        unsafe {
            ((*self.api).write_array_entry_begin)(transmute(self.api));
        }
    }

    pub fn array_entry_end(&mut self) {
        unsafe {
            ((*self.api).write_array_entry_end)(transmute(self.api));
        }
    }

    write_fun!(write_s8, i8);
    write_fun!(write_u8, u8);
    write_fun!(write_s16, i16);
    write_fun!(write_u16, u16);
    write_fun!(write_s32, i32);
    write_fun!(write_u32, u32);
    write_fun!(write_s64, i64);
    write_fun!(write_u64, u64);
    write_fun!(write_float, f32);
    write_fun!(write_double, f64);

    pub fn write_string(&mut self, id: &str, v: &str) {
        let id_s = CFixedString::from_str(id).as_ptr();
        let v_s = CFixedString::from_str(v).as_ptr();
        unsafe {
            ((*self.api).write_string)(transmute(self.api), id_s, v_s);
        }
    }

    pub fn write_data(&mut self, id: &str, data: &[u8]) {
        let s = CFixedString::from_str(id).as_ptr();
        unsafe {
            ((*self.api).write_data)(transmute(self.api),
                                     s,
                                     data.as_ptr(),
                                     data.len() as u32);
        }
    }
}
<commit_msg>Fixed crash when searhing for non-existing string<commit_after>use libc::*;
use std::mem::transmute;
use std::slice;
use std::str;
use CFixedString;

#[repr(C)]
pub struct CPDReaderAPI {
    pub data: *mut c_void,
    pub read_get_event: extern fn(reader: *mut c_void) -> uint32_t,
    pub read_iterator_next_event: extern fn(reader: *mut c_void,
                                            it: *mut uint64_t) -> uint32_t,
    pub read_iterator_begin: extern fn(reader: *mut c_void, it: *mut uint64_t,
                                       keyName: *mut *const c_char, parentIt: uint64_t)
                                    -> uint32_t,
    pub read_iterator_next: extern fn(reader: *mut c_void, keyName: *mut *const c_char,
                                      it: *mut uint64_t) -> uint32_t,
    pub read_next_entry: extern fn(reader: *mut c_void, arrayIt: *mut uint64_t)
                                -> int32_t,
    pub read_find_s8: extern fn(reader: *mut c_void, res: *mut int8_t, id: *const c_char,
                                it: uint64_t) -> uint32_t,
    pub read_find_u8: extern fn(reader: *mut c_void, res: *mut uint8_t, id: *const c_char,
                                it: uint64_t) -> uint32_t,
    pub read_find_s16: extern fn(reader: *mut c_void, res: *mut int16_t, id: *const c_char,
                                 it: uint64_t) -> uint32_t,
    pub read_find_u16: extern fn(reader: *mut c_void, res: *mut uint16_t, id: *const c_char,
                                 it: uint64_t) -> uint32_t,
    pub read_find_s32: extern fn(reader: *mut c_void, res: *mut int32_t, id: *const c_char,
                                 it: uint64_t) -> uint32_t,
    pub read_find_u32: extern fn(reader: *mut c_void, res: *mut uint32_t, id: *const c_char,
                                 it: uint64_t) -> uint32_t,
    pub read_find_s64: extern fn(reader: *mut c_void, res: *mut int64_t, id: *const c_char,
                                 it: uint64_t) -> uint32_t,
    pub read_find_u64: extern fn(reader: *mut c_void, res: *mut uint64_t, id: *const c_char,
                                 it: uint64_t) -> uint32_t,
    pub read_find_float: extern fn(reader: *mut c_void, res: *mut c_float, id: *const c_char,
                                   it: uint64_t) -> uint32_t,
    pub read_find_double: extern fn(reader: *mut c_void, res: *mut c_double, id: *const c_char,
                                    it: uint64_t) -> uint32_t,
    pub read_find_string: extern fn(reader: *mut c_void, res: *mut *const c_char, id: *const c_char,
                                    it: uint64_t) -> uint32_t,
    pub read_find_data: extern fn(reader: *mut c_void, data: *mut *mut c_void, size: *mut uint64_t,
                                  id: *const c_char, it: uint64_t) -> uint32_t,
    pub read_find_array: extern fn(reader: *mut c_void, arrayIt: *mut uint64_t, id: *const c_char,
                                   it: uint64_t) -> uint32_t,
    pub read_dump_data: extern fn(reader: *mut c_void),
}

#[repr(C)]
pub enum WriteStatus {
    Ok,
    Fail,
}

#[repr(C)]
pub struct CPDWriterAPI {
    private_data: *mut c_void,
    pub write_event_begin: extern "C" fn(writer: *mut c_void, event: uint16_t) -> WriteStatus,
    pub write_event_end: extern fn(writer: *mut c_void) -> WriteStatus,
    pub write_header_array_begin: extern fn(writer: *mut c_void, ids: *mut *const c_char)
                                         -> WriteStatus,
    pub write_header_array_end: extern fn(writer: *mut c_void) -> WriteStatus,
    pub write_array_begin: extern fn(writer: *mut c_void, name: *const c_char) -> WriteStatus,
    pub write_array_end: extern fn(writer: *mut c_void) -> WriteStatus,
    pub write_array_entry_begin: extern fn(writer: *mut c_void) -> WriteStatus,
    pub write_array_entry_end: extern fn(writer: *mut c_void) -> WriteStatus,
    pub write_s8: extern fn(writer: *mut c_void, id: *const c_char, v: int8_t) -> WriteStatus,
    pub write_u8: extern fn(writer: *mut c_void, id: *const c_char, v: uint8_t) -> WriteStatus,
    pub write_s16: extern fn(writer: *mut c_void, id: *const c_char, v: int16_t) -> WriteStatus,
    pub write_u16: extern fn(writer: *mut c_void, id: *const c_char, v: uint16_t) -> WriteStatus,
    pub write_s32: extern fn(writer: *mut c_void, id: *const c_char, v: int32_t) -> WriteStatus,
    pub write_u32: extern fn(writer: *mut c_void, id: *const c_char, v: uint32_t) -> WriteStatus,
    pub write_s64: extern fn(writer: *mut c_void, id: *const c_char, v: int64_t) -> WriteStatus,
    pub write_u64: extern fn(writer: *mut c_void, id: *const c_char, v: uint64_t) -> WriteStatus,
    pub write_float: extern fn(writer: *mut c_void, id: *const c_char, v: c_float) -> WriteStatus,
    pub write_double: extern fn(writer: *mut c_void, id: *const c_char, v: c_double) -> WriteStatus,
    pub write_string: extern fn(writer: *mut c_void, id: *const c_char, v: *const c_char)
                             -> WriteStatus,
    pub write_data: extern fn(w: *mut c_void, id: *const c_char, d: *const uint8_t, l: c_uint)
                            -> WriteStatus,
}

pub struct Reader {
    pub api: *mut CPDReaderAPI,
    pub it: u64,
}

pub struct Writer {
    pub api: *mut CPDWriterAPI,
}

#[repr(C)]
pub enum ReadType {
    None,
    S8,
    U8,
    S16,
    U16,
    S32,
    U32,
    S64,
    U64,
    Float,
    Double,
    EndNumericTypes,
    Str,
    Data,
    Event,
    Array,
    ArrayEntry,
    Count,
}

#[repr(C)]
pub enum ReadStatus {
    Ok = 1 << 8,
    Converted = 2 << 8,
    IllegalType = 3 << 8,
    NotFound = 4 << 8,
    Fail = 5 << 8,
    TypeMask = 0xff,
}

pub struct ReaderIter {
    reader: Reader,
    curr_iter: u64,
}

pub struct EventIter {
    reader: Reader,
}

impl Clone for Reader {
    fn clone(&self) -> Self {
        return Reader {
            api: self.api,
            it: self.it,
        };
    }
}

fn status_res<T>(res: T, s: u32) -> Result<T, ReadStatus> {
    match (s >> 8) & 0xff {
        1...2 => Ok(res),
        3 => Err(ReadStatus::IllegalType),
        _ => Err(ReadStatus::NotFound),
    }
}

macro_rules! find_fun {
    ($c_name:ident, $name:ident, $data_type:ident) => {
        pub fn $name(&self, id: &str) -> Result<$data_type, ReadStatus> {
            let s = CFixedString::from_str(id).as_ptr();
            let mut res = 0 as $data_type;
            let ret;

            unsafe {
                ret = ((*self.api).$c_name)(transmute(self.api), &mut res, s, self.it);
            }

            return status_res(res, ret);
        }
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

impl Reader {
    pub fn new(in_api: *mut CPDReaderAPI, iter: u64) -> Self {
        return Reader {
            api: in_api,
            it: iter,
        };
    }

    pub fn get_events(&self) -> EventIter {
        EventIter {
            reader: self.clone(),
        }
    }

    pub fn get_event(&self) -> Option<i32> {
        let event_id = unsafe {
            ((*self.api).read_get_event)(transmute(self.api)) as i32
        };

        match event_id {
            0 => None,
            e => Some(e),
        }
    }

    find_fun!(read_find_s8, find_s8, i8);
    find_fun!(read_find_u8, find_u8, u8);
    find_fun!(read_find_s16, find_s16, i16);
    find_fun!(read_find_u16, find_u16, u16);
    find_fun!(read_find_s32, find_s32, i32);
    find_fun!(read_find_u32, find_u32, u32);
    find_fun!(read_find_s64, find_s64, i64);
    find_fun!(read_find_u64, find_u64, u64);
    find_fun!(read_find_float, find_float, f32);
    find_fun!(read_find_double, find_double, f64);

    unsafe fn strlen(t: *const i8) -> usize{
        // very lange slice so this is kinda hacky but should work
        let slice = slice::from_raw_parts(t, 16834);
        let mut count = 0;

        loop {
            if slice[count] == 0 { break; }
            count += 1;
        }

        count
    }

    pub fn find_string(&self, id: &str) -> Result<&str, ReadStatus> {
        let s = CFixedString::from_str(id).as_ptr();
        let mut temp = 0 as *const c_char;
        let ret;
        let mut res = "";

        unsafe {
            ret = ((*self.api).read_find_string)(transmute(self.api), &mut temp, s, self.it);
            let t = (ret >> 8) & 0xff;
            if t == 1 {
                let slice = slice::from_raw_parts(temp as *const u8, Self::strlen(temp));
                res = str::from_utf8(slice).unwrap();
            }
        }

        return status_res(res, ret);
    }

    pub fn find_array(&self, id: &str) -> ReaderIter {
        let s = CFixedString::from_str(id).as_ptr();
        let mut t = 0u64;

        unsafe {
            ((*self.api).read_find_array)(transmute(self.api), &mut t, s, 0);
        }

        ReaderIter {
            reader: self.clone(),
            curr_iter: t,
        }
    }
}

impl Iterator for ReaderIter {
    type Item = Reader;
    fn next(&mut self) -> Option<Reader> {
        let ret;
        unsafe {
            ret = ((*self.reader.api).read_next_entry)(transmute(self.reader.api),
                                                       &mut self.curr_iter);
        }

        match ret {
            0 => None,
            _ => Some(Reader::new(self.reader.api, self.curr_iter)),
        }
    }
}

impl Iterator for EventIter {
    type Item = i32;
    fn next(&mut self) -> Option<i32> {
        self.reader.get_event()
    }
}

macro_rules! write_fun {
    ($name:ident, $data_type:ident) => {
        pub fn $name(&mut self, id: &str, v: $data_type) {
            let s = CFixedString::from_str(id).as_ptr();
            unsafe {
                ((*self.api).$name)(transmute(self.api), s, v);
            }
        }
    }
}

impl Writer {
    pub fn event_begin(&mut self, event: u16) {
        unsafe {
            ((*self.api).write_event_begin)(transmute(self.api), event);
        }
    }

    pub fn event_end(&mut self) {
        unsafe {
            ((*self.api).write_event_end)(transmute(self.api));
        }
    }

    pub fn array_begin(&mut self, name: &str) {
        let s = CFixedString::from_str(name).as_ptr();
        unsafe {
            ((*self.api).write_array_begin)(transmute(self.api), s);
        }
    }

    pub fn array_end(&mut self) {
        unsafe {
            ((*self.api).write_array_end)(transmute(self.api));
        }
    }

    pub fn array_entry_begin(&mut self) {
        unsafe {
            ((*self.api).write_array_entry_begin)(transmute(self.api));
        }
    }

    pub fn array_entry_end(&mut self) {
        unsafe {
            ((*self.api).write_array_entry_end)(transmute(self.api));
        }
    }

    write_fun!(write_s8, i8);
    write_fun!(write_u8, u8);
    write_fun!(write_s16, i16);
    write_fun!(write_u16, u16);
    write_fun!(write_s32, i32);
    write_fun!(write_u32, u32);
    write_fun!(write_s64, i64);
    write_fun!(write_u64, u64);
    write_fun!(write_float, f32);
    write_fun!(write_double, f64);

    pub fn write_string(&mut self, id: &str, v: &str) {
        let id_s = CFixedString::from_str(id).as_ptr();
        let v_s = CFixedString::from_str(v).as_ptr();
        unsafe {
            ((*self.api).write_string)(transmute(self.api), id_s, v_s);
        }
    }

    pub fn write_data(&mut self, id: &str, data: &[u8]) {
        let s = CFixedString::from_str(id).as_ptr();
        unsafe {
            ((*self.api).write_data)(transmute(self.api),
                                     s,
                                     data.as_ptr(),
                                     data.len() as u32);
        }
    }
}
<|endoftext|>


<commit_before>use regex::Regex;
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

use super::file::{FileHeaderSpec, FileHeaderData};

pub struct ParserError {
    summary: String,
    parsertext: String,
    index: i32,
    explanation: Option<String>,
}

impl ParserError {
    pub fn new(sum: &'static str, text: String, idx: i32, expl: &'static str) -> ParserError {
        ParserError {
            summary: String::from(sum),
            parsertext: text,
            index: idx,
            explanation: Some(String::from(expl)),
        }
    }

    pub fn short(sum: &str, text: String, idx: i32) -> ParserError {
        ParserError {
            summary: String::from(sum),
            parsertext: text,
            index: idx,
            explanation: None
        }
    }
}

impl Error for ParserError {

    fn description(&self) -> &str {
        &self.summary[..]
    }

}

impl Debug for ParserError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "ParserError: {}\n\n", self.summary);

        if let Some(ref e) = self.explanation {
            write!(fmt, "{}\n\n", e);
        }

        write!(fmt, "On position {}\nin\n{}", self.index, self.parsertext);
        Ok(())
    }

}

impl Display for ParserError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "ParserError: {}", self.summary);

        if let Some(ref e) = self.explanation {
            write!(fmt, "\n\n{}", e);
        }

        Ok(())
    }

}

pub trait FileHeaderParser : Sized {
    fn read(&self, string: Option<String>) -> Result<FileHeaderData, ParserError>;
    fn write(&self, data: &FileHeaderData) -> Result<String, ParserError>;
}

type TextTpl = (Option<String>, Option<String>);

pub struct Parser<HP>
{
    headerp : HP,
}

impl<HP> Parser<HP> where
    HP: FileHeaderParser,
{

    pub fn new(headerp: HP) -> Parser<HP> {
        Parser {
            headerp: headerp,
        }
    }

    pub fn read(&self, s: String) -> Result<(FileHeaderData, String), ParserError>
    {
        debug!("Reading into internal datastructure: '{}'", s);
        let divided = self.divide_text(&s);

        if divided.is_err() {
            debug!("Error reading into internal datastructure");
            return Err(divided.err().unwrap());
        }

        let (header, data) = divided.ok().unwrap();
        debug!("Header = '{:?}'", header);
        debug!("Data   = '{:?}'", data);

        let h_parseres = try!(self.headerp.read(header));
        debug!("Success parsing header");

        Ok((h_parseres, data.unwrap_or(String::new())))
    }

    pub fn write(&self, tpl : (FileHeaderData, String)) -> Result<String, ParserError>
    {
        debug!("Parsing internal datastructure to String");
        let (header, data) = tpl;
        let h_text = try!(self.headerp.write(&header));
        debug!("Success translating header");

        Ok(h_text + &data[..])
    }

    fn divide_text(&self, text: &String) -> Result<TextTpl, ParserError> {
        debug!("Splitting: '{}'", text);
        let re = Regex::new(r"(?m)^\-\-\-$\n(.*)^\-\-\-$\n(.*)").unwrap();

        let captures = re.captures(&text[..]).unwrap_or(
            return Err(ParserError::new("Cannot run regex on text",
                                        text.clone(), 0,
                                        "Cannot run regex on text to divide it into header and content."))
        );

        if captures.len() != 2 {
            return Err(ParserError::new("Unexpected Regex output",
                                        text.clone(), 0,
                                        "The regex to divide text into header and content had an unexpected output."))
        }

        let header  = captures.at(0).map(|s| String::from(s));
        let content = captures.at(1).map(|s| String::from(s));

        debug!("Splitted, Header = '{:?}'", header);
        debug!("Splitted, Data   = '{:?}'", content);
        Ok((header, content))
    }

}

<commit_msg>Fix: Output formatting<commit_after>use regex::Regex;
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

use super::file::{FileHeaderSpec, FileHeaderData};

pub struct ParserError {
    summary: String,
    parsertext: String,
    index: i32,
    explanation: Option<String>,
}

impl ParserError {
    pub fn new(sum: &'static str, text: String, idx: i32, expl: &'static str) -> ParserError {
        ParserError {
            summary: String::from(sum),
            parsertext: text,
            index: idx,
            explanation: Some(String::from(expl)),
        }
    }

    pub fn short(sum: &str, text: String, idx: i32) -> ParserError {
        ParserError {
            summary: String::from(sum),
            parsertext: text,
            index: idx,
            explanation: None
        }
    }
}

impl Error for ParserError {

    fn description(&self) -> &str {
        &self.summary[..]
    }

}

impl Debug for ParserError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "ParserError: {}\n\n", self.summary);

        if let Some(ref e) = self.explanation {
            write!(fmt, "{}\n\n", e);
        }

        write!(fmt, "On position {}\nin\n{}", self.index, self.parsertext);
        Ok(())
    }

}

impl Display for ParserError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "ParserError: {}", self.summary);

        if let Some(ref e) = self.explanation {
            write!(fmt, "\n\n{}", e);
        }

        Ok(())
    }

}

pub trait FileHeaderParser : Sized {
    fn read(&self, string: Option<String>) -> Result<FileHeaderData, ParserError>;
    fn write(&self, data: &FileHeaderData) -> Result<String, ParserError>;
}

type TextTpl = (Option<String>, Option<String>);

pub struct Parser<HP>
{
    headerp : HP,
}

impl<HP> Parser<HP> where
    HP: FileHeaderParser,
{

    pub fn new(headerp: HP) -> Parser<HP> {
        Parser {
            headerp: headerp,
        }
    }

    pub fn read(&self, s: String) -> Result<(FileHeaderData, String), ParserError>
    {
        debug!("Reading into internal datastructure: '{}'", s);
        let divided = self.divide_text(&s);

        if divided.is_err() {
            debug!("Error reading into internal datastructure");
            return Err(divided.err().unwrap());
        }

        let (header, data) = divided.ok().unwrap();
        debug!("Header = '{:?}'", header);
        debug!("Data   = '{:?}'", data);

        let h_parseres = try!(self.headerp.read(header));
        debug!("Success parsing header");

        Ok((h_parseres, data.unwrap_or(String::new())))
    }

    pub fn write(&self, tpl : (FileHeaderData, String)) -> Result<String, ParserError>
    {
        debug!("Parsing internal datastructure to String");
        let (header, data) = tpl;
        let h_text = try!(self.headerp.write(&header));
        debug!("Success translating header");

        let text = format!("---\n{}\n---\n{}", h_text, data);
        Ok(text)
    }

    fn divide_text(&self, text: &String) -> Result<TextTpl, ParserError> {
        debug!("Splitting: '{}'", text);
        let re = Regex::new(r"(?m)^\-\-\-$\n(.*)^\-\-\-$\n(.*)").unwrap();

        let captures = re.captures(&text[..]).unwrap_or(
            return Err(ParserError::new("Cannot run regex on text",
                                        text.clone(), 0,
                                        "Cannot run regex on text to divide it into header and content."))
        );

        if captures.len() != 2 {
            return Err(ParserError::new("Unexpected Regex output",
                                        text.clone(), 0,
                                        "The regex to divide text into header and content had an unexpected output."))
        }

        let header  = captures.at(0).map(|s| String::from(s));
        let content = captures.at(1).map(|s| String::from(s));

        debug!("Splitted, Header = '{:?}'", header);
        debug!("Splitted, Data   = '{:?}'", content);
        Ok((header, content))
    }

}

<|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::baseaudiocontext::BaseAudioContext;
use dom::bindings::codegen::Bindings::AudioNodeBinding::{AudioNodeMethods, AudioNodeOptions};
use dom::bindings::codegen::Bindings::AudioNodeBinding::{ChannelCountMode, ChannelInterpretation};
use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::root::{Dom, DomRoot};
use dom::audioparam::AudioParam;
use dom::eventtarget::EventTarget;
use dom_struct::dom_struct;
use servo_media::audio::graph::NodeId;
use servo_media::audio::node::{AudioNodeMessage, AudioNodeInit};
use std::cell::Cell;

// 32 is the minimum required by the spec for createBuffer() and the deprecated
// createScriptProcessor() and matches what is used by Blink and Gecko.
// The limit protects against large memory allocations.
pub const MAX_CHANNEL_COUNT: u32 = 32;

#[dom_struct]
pub struct AudioNode {
    eventtarget: EventTarget,
    #[ignore_malloc_size_of = "servo_media"]
    node_id: NodeId,
    context: Dom<BaseAudioContext>,
    number_of_inputs: u32,
    number_of_outputs: u32,
    channel_count: Cell<u32>,
    channel_count_mode: Cell<ChannelCountMode>,
    channel_interpretation: Cell<ChannelInterpretation>,
}

impl AudioNode {
    pub fn new_inherited(node_type: AudioNodeInit,
                         node_id: Option<NodeId>,
                         context: &BaseAudioContext,
                         options: &AudioNodeOptions,
                         number_of_inputs: u32,
                         number_of_outputs: u32) -> AudioNode {
        let node_id = node_id.unwrap_or_else(|| {
            context.audio_context_impl().create_node(node_type)
        });
        AudioNode {
            eventtarget: EventTarget::new_inherited(),
            node_id,
            context: Dom::from_ref(context),
            number_of_inputs,
            number_of_outputs,
            channel_count: Cell::new(options.channelCount.unwrap_or(2)),
            channel_count_mode: Cell::new(options.channelCountMode.unwrap_or_default()),
            channel_interpretation: Cell::new(options.channelInterpretation.unwrap_or_default()),
        }
    }

    pub fn message(&self, message: AudioNodeMessage) {
        self.context.audio_context_impl().message_node(self.node_id, message);
    }

    pub fn node_id(&self) -> NodeId {
        self.node_id
    }
}

impl AudioNodeMethods for AudioNode {
    // https://webaudio.github.io/web-audio-api/#dom-audionode-connect
    fn Connect(&self,
               destination: &AudioNode,
               output: u32,
               input: u32) -> Fallible<DomRoot<AudioNode>> {
        if *(self.context) != *(destination.Context()) {
            //XXX return Err(Error::InvalidAccess);
        }

        if output >= self.NumberOfOutputs() ||
            input >= destination.NumberOfInputs() {
                return Err(Error::IndexSize);
            }

        // XXX Check previous connections.

        self.context.audio_context_impl().connect_ports(
            self.node_id().output(output), destination.node_id().input(input)
            );

        Ok(DomRoot::from_ref(destination))
    }

    fn Connect_(&self,
                _: &AudioParam,
                _: u32) -> Fallible<()> {
        // TODO
        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audionode-disconnect
    fn Disconnect(&self) -> ErrorResult {
        self.context.audio_context_impl()
            .disconnect_all_from(self.node_id());
        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audionode-disconnect-output
    fn Disconnect_(&self, out: u32) -> ErrorResult {
        self.context.audio_context_impl()
            .disconnect_output(self.node_id().output(out));
        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audionode-disconnect-destinationnode
    fn Disconnect__(&self, to: &AudioNode) -> ErrorResult {
        self.context.audio_context_impl()
            .disconnect_between(self.node_id(), to.node_id());
        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audionode-disconnect-destinationnode-output
    fn Disconnect___(&self, to: &AudioNode, out: u32) -> ErrorResult{
        self.context.audio_context_impl()
            .disconnect_output_between(self.node_id().output(out), to.node_id());
        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audionode-disconnect-destinationnode-output-input
    fn Disconnect____(&self, to: &AudioNode, out: u32, inp: u32) -> ErrorResult {
        self.context.audio_context_impl()
            .disconnect_output_between_to(self.node_id().output(out), to.node_id().input(inp));
        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audionode-disconnect
    fn Disconnect_____(&self, _: &AudioParam) -> ErrorResult {
        // TODO
        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audionode-disconnect
    fn Disconnect______(&self, _: &AudioParam, _: u32) -> ErrorResult {
        // TODO
        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audionode-context
    fn Context(&self) -> DomRoot<BaseAudioContext> {
        DomRoot::from_ref(&self.context)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audionode-numberofinputs
    fn NumberOfInputs(&self) -> u32 {
        self.number_of_inputs
    }

    // https://webaudio.github.io/web-audio-api/#dom-audionode-numberofoutputs
    fn NumberOfOutputs(&self) -> u32 {
        self.number_of_outputs
    }

    // https://webaudio.github.io/web-audio-api/#dom-audionode-channelcount
    fn ChannelCount(&self) -> u32 {
        self.channel_count.get()
    }

    fn SetChannelCount(&self, value: u32) -> ErrorResult {
        if value == 0 || value > MAX_CHANNEL_COUNT {
            return Err(Error::NotSupported);
        }
        self.channel_count.set(value);
        Ok(())
    }

    fn ChannelCountMode(&self) -> ChannelCountMode {
        self.channel_count_mode.get()
    }

    fn SetChannelCountMode(&self, value: ChannelCountMode) -> ErrorResult {
        self.channel_count_mode.set(value);
        Ok(())
    }

    fn ChannelInterpretation(&self) -> ChannelInterpretation {
        self.channel_interpretation.get()
    }

    fn SetChannelInterpretation(&self, value: ChannelInterpretation) {
        self.channel_interpretation.set(value);
    }
}
<commit_msg>Fix context comparison (#5)<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::baseaudiocontext::BaseAudioContext;
use dom::bindings::codegen::Bindings::AudioNodeBinding::{AudioNodeMethods, AudioNodeOptions};
use dom::bindings::codegen::Bindings::AudioNodeBinding::{ChannelCountMode, ChannelInterpretation};
use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::root::{Dom, DomRoot};
use dom::audioparam::AudioParam;
use dom::eventtarget::EventTarget;
use dom_struct::dom_struct;
use servo_media::audio::graph::NodeId;
use servo_media::audio::node::{AudioNodeMessage, AudioNodeInit};
use std::cell::Cell;

// 32 is the minimum required by the spec for createBuffer() and the deprecated
// createScriptProcessor() and matches what is used by Blink and Gecko.
// The limit protects against large memory allocations.
pub const MAX_CHANNEL_COUNT: u32 = 32;

#[dom_struct]
pub struct AudioNode {
    eventtarget: EventTarget,
    #[ignore_malloc_size_of = "servo_media"]
    node_id: NodeId,
    context: Dom<BaseAudioContext>,
    number_of_inputs: u32,
    number_of_outputs: u32,
    channel_count: Cell<u32>,
    channel_count_mode: Cell<ChannelCountMode>,
    channel_interpretation: Cell<ChannelInterpretation>,
}

impl AudioNode {
    pub fn new_inherited(node_type: AudioNodeInit,
                         node_id: Option<NodeId>,
                         context: &BaseAudioContext,
                         options: &AudioNodeOptions,
                         number_of_inputs: u32,
                         number_of_outputs: u32) -> AudioNode {
        let node_id = node_id.unwrap_or_else(|| {
            context.audio_context_impl().create_node(node_type)
        });
        AudioNode {
            eventtarget: EventTarget::new_inherited(),
            node_id,
            context: Dom::from_ref(context),
            number_of_inputs,
            number_of_outputs,
            channel_count: Cell::new(options.channelCount.unwrap_or(2)),
            channel_count_mode: Cell::new(options.channelCountMode.unwrap_or_default()),
            channel_interpretation: Cell::new(options.channelInterpretation.unwrap_or_default()),
        }
    }

    pub fn message(&self, message: AudioNodeMessage) {
        self.context.audio_context_impl().message_node(self.node_id, message);
    }

    pub fn node_id(&self) -> NodeId {
        self.node_id
    }
}

impl AudioNodeMethods for AudioNode {
    // https://webaudio.github.io/web-audio-api/#dom-audionode-connect
    fn Connect(&self,
               destination: &AudioNode,
               output: u32,
               input: u32) -> Fallible<DomRoot<AudioNode>> {
        if self.context != destination.context {
            return Err(Error::InvalidAccess);
        }

        if output >= self.NumberOfOutputs() ||
            input >= destination.NumberOfInputs() {
                return Err(Error::IndexSize);
            }

        // XXX Check previous connections.

        self.context.audio_context_impl().connect_ports(
            self.node_id().output(output), destination.node_id().input(input)
            );

        Ok(DomRoot::from_ref(destination))
    }

    fn Connect_(&self,
                _: &AudioParam,
                _: u32) -> Fallible<()> {
        // TODO
        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audionode-disconnect
    fn Disconnect(&self) -> ErrorResult {
        self.context.audio_context_impl()
            .disconnect_all_from(self.node_id());
        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audionode-disconnect-output
    fn Disconnect_(&self, out: u32) -> ErrorResult {
        self.context.audio_context_impl()
            .disconnect_output(self.node_id().output(out));
        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audionode-disconnect-destinationnode
    fn Disconnect__(&self, to: &AudioNode) -> ErrorResult {
        self.context.audio_context_impl()
            .disconnect_between(self.node_id(), to.node_id());
        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audionode-disconnect-destinationnode-output
    fn Disconnect___(&self, to: &AudioNode, out: u32) -> ErrorResult{
        self.context.audio_context_impl()
            .disconnect_output_between(self.node_id().output(out), to.node_id());
        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audionode-disconnect-destinationnode-output-input
    fn Disconnect____(&self, to: &AudioNode, out: u32, inp: u32) -> ErrorResult {
        self.context.audio_context_impl()
            .disconnect_output_between_to(self.node_id().output(out), to.node_id().input(inp));
        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audionode-disconnect
    fn Disconnect_____(&self, _: &AudioParam) -> ErrorResult {
        // TODO
        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audionode-disconnect
    fn Disconnect______(&self, _: &AudioParam, _: u32) -> ErrorResult {
        // TODO
        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audionode-context
    fn Context(&self) -> DomRoot<BaseAudioContext> {
        DomRoot::from_ref(&self.context)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audionode-numberofinputs
    fn NumberOfInputs(&self) -> u32 {
        self.number_of_inputs
    }

    // https://webaudio.github.io/web-audio-api/#dom-audionode-numberofoutputs
    fn NumberOfOutputs(&self) -> u32 {
        self.number_of_outputs
    }

    // https://webaudio.github.io/web-audio-api/#dom-audionode-channelcount
    fn ChannelCount(&self) -> u32 {
        self.channel_count.get()
    }

    fn SetChannelCount(&self, value: u32) -> ErrorResult {
        if value == 0 || value > MAX_CHANNEL_COUNT {
            return Err(Error::NotSupported);
        }
        self.channel_count.set(value);
        Ok(())
    }

    fn ChannelCountMode(&self) -> ChannelCountMode {
        self.channel_count_mode.get()
    }

    fn SetChannelCountMode(&self, value: ChannelCountMode) -> ErrorResult {
        self.channel_count_mode.set(value);
        Ok(())
    }

    fn ChannelInterpretation(&self) -> ChannelInterpretation {
        self.channel_interpretation.get()
    }

    fn SetChannelInterpretation(&self, value: ChannelInterpretation) {
        self.channel_interpretation.set(value);
    }
}
<|endoftext|>