<commit_before>//! This crate provides Serde's two derive macros.
//!
//! ```edition2018
//! # use serde_derive::{Serialize, Deserialize};
//! #
//! #[derive(Serialize, Deserialize)]
//! # struct S;
//! #
//! # fn main() {}
//! ```
//!
//! Please refer to [https://serde.rs/derive.html] for how to set this up.
//!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html

#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.104")]
#![allow(unknown_lints, bare_trait_objects)]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Ignored clippy lints
#![cfg_attr(
    feature = "cargo-clippy",
    allow(
        cognitive_complexity,
        enum_variant_names,
        needless_pass_by_value,
        redundant_field_names,
        too_many_arguments,
        trivially_copy_pass_by_ref,
        used_underscore_binding,
        wildcard_in_or_patterns,
    )
)]
// Ignored clippy_pedantic lints
#![cfg_attr(
    feature = "cargo-clippy",
    allow(
        cast_possible_truncation,
        checked_conversions,
        doc_markdown,
        enum_glob_use,
        filter_map,
        indexing_slicing,
        items_after_statements,
        match_same_arms,
        module_name_repetitions,
        must_use_candidate,
        similar_names,
        single_match_else,
        too_many_lines,
        unseparated_literal_suffix,
        use_self,
    )
)]
// The `quote!` macro requires deep recursion.
#![recursion_limit = "512"]

#[macro_use]
extern crate quote;
#[macro_use]
extern crate syn;

extern crate proc_macro;
extern crate proc_macro2;

mod internals;

use proc_macro::TokenStream;
use syn::DeriveInput;

#[macro_use]
mod bound;
#[macro_use]
mod fragment;

mod de;
mod dummy;
mod pretend;
mod ser;
mod try;

#[proc_macro_derive(Serialize, attributes(serde))]
pub fn derive_serialize(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    ser::expand_derive_serialize(&input)
        .unwrap_or_else(to_compile_errors)
        .into()
}

#[proc_macro_derive(Deserialize, attributes(serde))]
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    de::expand_derive_deserialize(&input)
        .unwrap_or_else(to_compile_errors)
        .into()
}

fn to_compile_errors(errors: Vec<syn::Error>) -> proc_macro2::TokenStream {
    let compile_errors = errors.iter().map(syn::Error::to_compile_error);
    quote!(#(#compile_errors)*)
}
<commit_msg>Ignore struct_excessive_bools pedantic lint<commit_after>//! This crate provides Serde's two derive macros.
//!
//! ```edition2018
//! # use serde_derive::{Serialize, Deserialize};
//! #
//! #[derive(Serialize, Deserialize)]
//! # struct S;
//! #
//! # fn main() {}
//! ```
//!
//! Please refer to [https://serde.rs/derive.html] for how to set this up.
//!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html

#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.104")]
#![allow(unknown_lints, bare_trait_objects)]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Ignored clippy lints
#![cfg_attr(
    feature = "cargo-clippy",
    allow(
        cognitive_complexity,
        enum_variant_names,
        needless_pass_by_value,
        redundant_field_names,
        too_many_arguments,
        trivially_copy_pass_by_ref,
        used_underscore_binding,
        wildcard_in_or_patterns,
    )
)]
// Ignored clippy_pedantic lints
#![cfg_attr(
    feature = "cargo-clippy",
    allow(
        cast_possible_truncation,
        checked_conversions,
        doc_markdown,
        enum_glob_use,
        filter_map,
        indexing_slicing,
        items_after_statements,
        match_same_arms,
        module_name_repetitions,
        must_use_candidate,
        similar_names,
        single_match_else,
        struct_excessive_bools,
        too_many_lines,
        unseparated_literal_suffix,
        use_self,
    )
)]
// The `quote!` macro requires deep recursion.
#![recursion_limit = "512"]

#[macro_use]
extern crate quote;
#[macro_use]
extern crate syn;

extern crate proc_macro;
extern crate proc_macro2;

mod internals;

use proc_macro::TokenStream;
use syn::DeriveInput;

#[macro_use]
mod bound;
#[macro_use]
mod fragment;

mod de;
mod dummy;
mod pretend;
mod ser;
mod try;

#[proc_macro_derive(Serialize, attributes(serde))]
pub fn derive_serialize(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    ser::expand_derive_serialize(&input)
        .unwrap_or_else(to_compile_errors)
        .into()
}

#[proc_macro_derive(Deserialize, attributes(serde))]
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    de::expand_derive_deserialize(&input)
        .unwrap_or_else(to_compile_errors)
        .into()
}

fn to_compile_errors(errors: Vec<syn::Error>) -> proc_macro2::TokenStream {
    let compile_errors = errors.iter().map(syn::Error::to_compile_error);
    quote!(#(#compile_errors)*)
}
<|endoftext|>


<commit_before>use std;

use std::borrow::Borrow;
use std::ops::Deref;
use std::ptr;
use std::str;

use crlf;
use smallvec::{Array, SmallVec};
use str_utils::{char_idx_to_byte_idx, count_chars};
use tree::MAX_BYTES;

/// A custom small string, with an internal buffer of `tree::MAX_BYTES`
/// length.  Has a bunch of methods on it that are useful for the rope
/// tree.
#[derive(Clone, Default)]
pub(crate) struct NodeText {
    buffer: SmallVec<BackingArray>,
}

impl NodeText {
    /// Creates a new empty `NodeText`
    #[inline(always)]
    pub fn new() -> Self {
        NodeText {
            buffer: SmallVec::new(),
        }
    }

    /// Creates a new empty `NodeText` with at least `capacity` bytes
    /// of capacity.
    #[inline(always)]
    pub fn with_capacity(capacity: usize) -> Self {
        NodeText {
            buffer: SmallVec::with_capacity(capacity),
        }
    }

    /// Creates a new `NodeText` with the same contents as the given `&str`.
    pub fn from_str(string: &str) -> Self {
        debug_assert!(string.len() <= MAX_BYTES);
        let mut nodetext = NodeText::with_capacity(string.len());
        unsafe { nodetext.insert_bytes(0, string.as_bytes()) };
        nodetext
    }

    /// Inserts a `&str` at byte offset `idx`.
    ///
    /// Panics if `idx` is not a char boundary, as that would result in an
    /// invalid utf8 string.
    pub fn insert_str(&mut self, byte_idx: usize, string: &str) {
        debug_assert!(self.is_char_boundary(byte_idx));
        debug_assert!(byte_idx <= self.len());
        debug_assert!((self.len() + string.len()) <= MAX_BYTES);

        unsafe {
            self.insert_bytes(byte_idx, string.as_bytes());
        }
    }

    /// Inserts the given text into the given string at the given char index.
    pub fn insert_str_at_char(&mut self, text: &str, char_idx: usize) {
        debug_assert!((self.len() + text.len()) <= MAX_BYTES);
        let byte_idx = char_idx_to_byte_idx(self, char_idx);
        self.insert_str(byte_idx, text);
    }

    /// Inserts a `&str` and splits the resulting string in half, returning
    /// the right half.
    ///
    /// Only splits on code point boundaries and will never split CRLF pairs,
    /// grapheme boundaries, so if the whole string is a single code point or
    /// CRLF pair, the split will fail and the returned string will be empty.
    pub fn insert_str_split(&mut self, idx: usize, string: &str) -> Self {
        debug_assert!(self.is_char_boundary(idx));
        debug_assert!((self.len() + string.len()) <= (MAX_BYTES * 2 - 4));

        let tot_len = self.len() + string.len();
        let mid_idx = tot_len / 2;
        let a = idx;
        let b = idx + string.len();

        // Figure out the split index, accounting for code point
        // boundaries and CRLF pairs.
        // We first copy the bytes in the area of the proposed split point into
        // a small 8-byte buffer.  We then use that buffer to look for the
        // real split point.
        let split_idx = {
            let mut buf = [0u8; 8];
            let start = mid_idx - 4.min(mid_idx);
            let end = (mid_idx + 4).min(tot_len);
            for i in start..end {
                buf[i - start] = if i < a {
                    self.as_bytes()[i]
                } else if i < b {
                    string.as_bytes()[i - a]
                } else {
                    self.as_bytes()[i - string.len()]
                };
            }

            crlf::nearest_internal_break(mid_idx - start, &buf[..(end - start)]) + start
        };

        debug_assert!(split_idx <= MAX_BYTES);

        let mut right = NodeText::new();
        if split_idx <= a {
            right.push_str(&self[split_idx..a]);
            right.push_str(string);
            right.push_str(&self[a..]);
            self.truncate(split_idx);
        } else if split_idx <= b {
            right.push_str(&string[(split_idx - a)..]);
            right.push_str(&self[a..]);
            self.truncate(a);
            self.push_str(&string[..(split_idx - a)]);
        } else {
            right.push_str(&self[(split_idx - string.len())..]);
            self.truncate(split_idx - string.len());
            self.insert_str(a, string);
        }

        right
    }

    /// Appends a `&str` to end the of the `NodeText`.
    pub fn push_str(&mut self, string: &str) {
        debug_assert!((self.len() + string.len()) <= MAX_BYTES);
        let len = self.len();
        unsafe {
            self.insert_bytes(len, string.as_bytes());
        }
    }

    /// Appends a `&str` and splits the resulting string in half, returning
    /// the right half.
    ///
    /// Only splits on code point boundaries and will never split CRLF pairs,
    /// grapheme boundaries, so if the whole string is a single code point or
    /// CRLF pair, the split will fail and the returned string will be empty.
    ///
    /// TODO: make this work without allocations when possible.
    pub fn push_str_split(&mut self, string: &str) -> Self {
        let len = self.len();
        self.insert_str_split(len, string)
    }

    /// Drops the text after byte index `idx`.
    ///
    /// Panics if `idx` is not a char boundary, as that would result in an
    /// invalid utf8 string.
    pub fn truncate(&mut self, idx: usize) {
        assert!(self.is_char_boundary(idx));
        debug_assert!(idx <= self.len());
        self.buffer.truncate(idx);
        self.inline_if_possible();
    }

    /// Drops the text before byte index `idx`, shifting the
    /// rest of the text to fill in the space.
    ///
    /// Panics if `idx` is not a char boundary, as that would result in an
    /// invalid utf8 string.
    pub fn truncate_front(&mut self, idx: usize) {
        assert!(self.is_char_boundary(idx));
        debug_assert!(idx <= self.len());
        unsafe {
            self.remove_bytes(0, idx);
        }
    }

    /// Removes the text in the byte index interval `[start, end)`.
    ///
    /// Panics if either `start` or `end` are not char boundaries, as that
    /// would result in an invalid utf8 string.
    pub fn remove_range(&mut self, start: usize, end: usize) {
        assert!(self.is_char_boundary(start));
        assert!(self.is_char_boundary(end));
        debug_assert!(end <= self.len());
        debug_assert!(start <= end);
        unsafe {
            self.remove_bytes(start, end);
        }
        self.inline_if_possible();
    }

    pub fn remove_char_range(&mut self, start: usize, end: usize) {
        debug_assert!(start <= end);
        debug_assert!(end <= count_chars(self));

        let byte_start = char_idx_to_byte_idx(self, start);
        let byte_end = char_idx_to_byte_idx(&self[start..], end - start);

        unsafe { self.remove_bytes(byte_start, byte_end) }
        self.inline_if_possible();
    }

    /// Splits the `NodeText` at `idx`.
    ///
    /// The left part remains in the original, and the right part is
    /// returned in a new `NodeText`.
    ///
    /// Panics if `idx` is not a char boundary, as that would result in an
    /// invalid utf8 string.
    pub fn split_off(&mut self, idx: usize) -> Self {
        assert!(self.is_char_boundary(idx));
        assert!(idx <= self.len());
        let len = self.len();
        let mut other = NodeText::with_capacity(len - idx);
        unsafe {
            ptr::copy_nonoverlapping(
                self.buffer.as_ptr().offset(idx as isize),
                other.buffer.as_mut_ptr().offset(0),
                len - idx,
            );
            self.buffer.set_len(idx);
            other.buffer.set_len(len - idx);
        }
        self.inline_if_possible();
        other
    }

    /// Splits a string into two strings at the char index given.
    /// The first section of the split is stored in the original string,
    /// while the second section of the split is returned as a new string.
    pub fn split_off_at_char(&mut self, char_idx: usize) -> Self {
        debug_assert!(char_idx <= count_chars(self));
        let byte_idx = char_idx_to_byte_idx(self, char_idx);
        self.split_off(byte_idx)
    }

    #[inline(always)]
    pub fn shrink_to_fit(&mut self) {
        self.buffer.shrink_to_fit();
    }

    /// Returns whether the string has spilled out into a heap-allocated
    /// memory area.
    pub fn spilled(&self) -> bool {
        self.buffer.spilled()
    }

    #[inline(always)]
    pub unsafe fn as_mut_smallvec(&mut self) -> &mut SmallVec<BackingArray> {
        &mut self.buffer
    }

    #[inline(always)]
    unsafe fn insert_bytes(&mut self, idx: usize, bytes: &[u8]) {
        assert!(idx <= self.len());
        debug_assert!((self.len() + bytes.len()) <= MAX_BYTES);

        let len = self.len();
        let amt = bytes.len();
        self.buffer.reserve(amt);

        ptr::copy(
            self.buffer.as_ptr().offset(idx as isize),
            self.buffer.as_mut_ptr().offset((idx + amt) as isize),
            len - idx,
        );
        ptr::copy(
            bytes.as_ptr(),
            self.buffer.as_mut_ptr().offset(idx as isize),
            amt,
        );
        self.buffer.set_len(len + amt);
    }

    #[inline(always)]
    unsafe fn remove_bytes(&mut self, start: usize, end: usize) {
        assert!(start <= end);
        assert!(end <= self.len());
        let len = self.len();
        let amt = end - start;
        ptr::copy(
            self.buffer.as_ptr().offset(end as isize),
            self.buffer.as_mut_ptr().offset(start as isize),
            len - end,
        );
        self.buffer.set_len(len - amt);

        self.inline_if_possible();
    }

    /// Re-inlines the data if it's been heap allocated but can
    /// fit inline.
    #[inline(always)]
    fn inline_if_possible(&mut self) {
        if self.buffer.spilled() && (self.buffer.len() <= self.buffer.inline_size()) {
            self.buffer.shrink_to_fit();
        }
    }
}

impl std::cmp::PartialEq for NodeText {
    fn eq(&self, other: &Self) -> bool {
        let (s1, s2): (&str, &str) = (self, other);
        s1 == s2
    }
}

impl<'a> PartialEq<NodeText> for &'a str {
    fn eq(&self, other: &NodeText) -> bool {
        *self == (other as &str)
    }
}

impl<'a> PartialEq<&'a str> for NodeText {
    fn eq(&self, other: &&'a str) -> bool {
        (self as &str) == *other
    }
}

impl std::fmt::Display for NodeText {
    fn fmt(&self, fm: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        NodeText::deref(self).fmt(fm)
    }
}

impl std::fmt::Debug for NodeText {
    fn fmt(&self, fm: &mut std::fmt::Formatter) -> std::fmt::Result {
        NodeText::deref(self).fmt(fm)
    }
}

impl<'a> From<&'a str> for NodeText {
    fn from(s: &str) -> Self {
        Self::from_str(s)
    }
}

impl Deref for NodeText {
    type Target = str;

    fn deref(&self) -> &str {
        // NodeText's methods don't allow `buffer` to become invalid utf8,
        // so this is safe.
        unsafe { str::from_utf8_unchecked(self.buffer.as_ref()) }
    }
}

impl AsRef<str> for NodeText {
    fn as_ref(&self) -> &str {
        // NodeText's methods don't allow `buffer` to become invalid utf8,
        // so this is safe.
        unsafe { str::from_utf8_unchecked(self.buffer.as_ref()) }
    }
}

impl Borrow<str> for NodeText {
    fn borrow(&self) -> &str {
        // NodeText's methods don't allow `buffer` to become invalid utf8,
        // so this is safe.
        unsafe { str::from_utf8_unchecked(self.buffer.as_ref()) }
    }
}

//=======================================================================

/// Takes two `NodeText`s and mends the segment break between them, if any.
///
/// Note: this will leave one of the strings empty if the entire composite string
/// is one big grapheme.
pub(crate) fn fix_segment_seam(l: &mut NodeText, r: &mut NodeText) {
    // Early out, if there's nothing to do.
    if crlf::seam_is_break(l.as_bytes(), r.as_bytes()) {
        return;
    }

    // Find the nearest breaks around the seam.
    let l_split = crlf::prev_break(l.len(), l.as_bytes());
    let r_split = l.len() + crlf::next_break(0, r.as_bytes());

    // Find the new split position, if any.
    let new_split_pos = {
        let tot_len = l.len() + r.len();
        if l_split != 0 && (r_split == tot_len || l.len() > r.len()) {
            l_split
        } else {
            r_split
        }
    };

    // Move the bytes to create the new split
    if new_split_pos < l.len() {
        r.insert_str(0, &l[new_split_pos..]);
        l.truncate(new_split_pos);
    } else {
        let pos = new_split_pos - l.len();
        l.push_str(&r[..pos]);
        r.truncate_front(pos);
    }
}

//=======================================================================

/// The backing internal buffer for `NodeText`.
#[derive(Copy, Clone)]
pub(crate) struct BackingArray([u8; MAX_BYTES]);
unsafe impl Array for BackingArray {
    type Item = u8;
    fn size() -> usize {
        MAX_BYTES
    }
    fn ptr(&self) -> *const u8 {
        &self.0[0]
    }
    fn ptr_mut(&mut self) -> *mut u8 {
        &mut self.0[0]
    }
}

//=======================================================================

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

    #[test]
    fn remove_bytes_01() {
        let mut s = NodeText::new();
        s.push_str("Hello!");
        unsafe {
            s.remove_bytes(2, 4);
        }
        assert_eq!("Heo!", s);
    }
}
<commit_msg>Fixed code comment.<commit_after>use std;

use std::borrow::Borrow;
use std::ops::Deref;
use std::ptr;
use std::str;

use crlf;
use smallvec::{Array, SmallVec};
use str_utils::{char_idx_to_byte_idx, count_chars};
use tree::MAX_BYTES;

/// A custom small string, with an internal buffer of `tree::MAX_BYTES`
/// length.  Has a bunch of methods on it that are useful for the rope
/// tree.
#[derive(Clone, Default)]
pub(crate) struct NodeText {
    buffer: SmallVec<BackingArray>,
}

impl NodeText {
    /// Creates a new empty `NodeText`
    #[inline(always)]
    pub fn new() -> Self {
        NodeText {
            buffer: SmallVec::new(),
        }
    }

    /// Creates a new empty `NodeText` with at least `capacity` bytes
    /// of capacity.
    #[inline(always)]
    pub fn with_capacity(capacity: usize) -> Self {
        NodeText {
            buffer: SmallVec::with_capacity(capacity),
        }
    }

    /// Creates a new `NodeText` with the same contents as the given `&str`.
    pub fn from_str(string: &str) -> Self {
        debug_assert!(string.len() <= MAX_BYTES);
        let mut nodetext = NodeText::with_capacity(string.len());
        unsafe { nodetext.insert_bytes(0, string.as_bytes()) };
        nodetext
    }

    /// Inserts a `&str` at byte offset `idx`.
    ///
    /// Panics if `idx` is not a char boundary, as that would result in an
    /// invalid utf8 string.
    pub fn insert_str(&mut self, byte_idx: usize, string: &str) {
        debug_assert!(self.is_char_boundary(byte_idx));
        debug_assert!(byte_idx <= self.len());
        debug_assert!((self.len() + string.len()) <= MAX_BYTES);

        unsafe {
            self.insert_bytes(byte_idx, string.as_bytes());
        }
    }

    /// Inserts the given text into the given string at the given char index.
    pub fn insert_str_at_char(&mut self, text: &str, char_idx: usize) {
        debug_assert!((self.len() + text.len()) <= MAX_BYTES);
        let byte_idx = char_idx_to_byte_idx(self, char_idx);
        self.insert_str(byte_idx, text);
    }

    /// Inserts a `&str` and splits the resulting string in half, returning
    /// the right half.
    ///
    /// Only splits on code point boundaries and will never split CRLF pairs,
    /// so if the whole string is a single code point or CRLF pair, the split
    /// will fail and the returned string will be empty.
    pub fn insert_str_split(&mut self, idx: usize, string: &str) -> Self {
        debug_assert!(self.is_char_boundary(idx));
        debug_assert!((self.len() + string.len()) <= (MAX_BYTES * 2 - 4));

        let tot_len = self.len() + string.len();
        let mid_idx = tot_len / 2;
        let a = idx;
        let b = idx + string.len();

        // Figure out the split index, accounting for code point
        // boundaries and CRLF pairs.
        // We first copy the bytes in the area of the proposed split point into
        // a small 8-byte buffer.  We then use that buffer to look for the
        // real split point.
        let split_idx = {
            let mut buf = [0u8; 8];
            let start = mid_idx - 4.min(mid_idx);
            let end = (mid_idx + 4).min(tot_len);
            for i in start..end {
                buf[i - start] = if i < a {
                    self.as_bytes()[i]
                } else if i < b {
                    string.as_bytes()[i - a]
                } else {
                    self.as_bytes()[i - string.len()]
                };
            }

            crlf::nearest_internal_break(mid_idx - start, &buf[..(end - start)]) + start
        };

        debug_assert!(split_idx <= MAX_BYTES);

        let mut right = NodeText::new();
        if split_idx <= a {
            right.push_str(&self[split_idx..a]);
            right.push_str(string);
            right.push_str(&self[a..]);
            self.truncate(split_idx);
        } else if split_idx <= b {
            right.push_str(&string[(split_idx - a)..]);
            right.push_str(&self[a..]);
            self.truncate(a);
            self.push_str(&string[..(split_idx - a)]);
        } else {
            right.push_str(&self[(split_idx - string.len())..]);
            self.truncate(split_idx - string.len());
            self.insert_str(a, string);
        }

        right
    }

    /// Appends a `&str` to end the of the `NodeText`.
    pub fn push_str(&mut self, string: &str) {
        debug_assert!((self.len() + string.len()) <= MAX_BYTES);
        let len = self.len();
        unsafe {
            self.insert_bytes(len, string.as_bytes());
        }
    }

    /// Appends a `&str` and splits the resulting string in half, returning
    /// the right half.
    ///
    /// Only splits on code point boundaries and will never split CRLF pairs,
    /// grapheme boundaries, so if the whole string is a single code point or
    /// CRLF pair, the split will fail and the returned string will be empty.
    ///
    /// TODO: make this work without allocations when possible.
    pub fn push_str_split(&mut self, string: &str) -> Self {
        let len = self.len();
        self.insert_str_split(len, string)
    }

    /// Drops the text after byte index `idx`.
    ///
    /// Panics if `idx` is not a char boundary, as that would result in an
    /// invalid utf8 string.
    pub fn truncate(&mut self, idx: usize) {
        assert!(self.is_char_boundary(idx));
        debug_assert!(idx <= self.len());
        self.buffer.truncate(idx);
        self.inline_if_possible();
    }

    /// Drops the text before byte index `idx`, shifting the
    /// rest of the text to fill in the space.
    ///
    /// Panics if `idx` is not a char boundary, as that would result in an
    /// invalid utf8 string.
    pub fn truncate_front(&mut self, idx: usize) {
        assert!(self.is_char_boundary(idx));
        debug_assert!(idx <= self.len());
        unsafe {
            self.remove_bytes(0, idx);
        }
    }

    /// Removes the text in the byte index interval `[start, end)`.
    ///
    /// Panics if either `start` or `end` are not char boundaries, as that
    /// would result in an invalid utf8 string.
    pub fn remove_range(&mut self, start: usize, end: usize) {
        assert!(self.is_char_boundary(start));
        assert!(self.is_char_boundary(end));
        debug_assert!(end <= self.len());
        debug_assert!(start <= end);
        unsafe {
            self.remove_bytes(start, end);
        }
        self.inline_if_possible();
    }

    pub fn remove_char_range(&mut self, start: usize, end: usize) {
        debug_assert!(start <= end);
        debug_assert!(end <= count_chars(self));

        let byte_start = char_idx_to_byte_idx(self, start);
        let byte_end = char_idx_to_byte_idx(&self[start..], end - start);

        unsafe { self.remove_bytes(byte_start, byte_end) }
        self.inline_if_possible();
    }

    /// Splits the `NodeText` at `idx`.
    ///
    /// The left part remains in the original, and the right part is
    /// returned in a new `NodeText`.
    ///
    /// Panics if `idx` is not a char boundary, as that would result in an
    /// invalid utf8 string.
    pub fn split_off(&mut self, idx: usize) -> Self {
        assert!(self.is_char_boundary(idx));
        assert!(idx <= self.len());
        let len = self.len();
        let mut other = NodeText::with_capacity(len - idx);
        unsafe {
            ptr::copy_nonoverlapping(
                self.buffer.as_ptr().offset(idx as isize),
                other.buffer.as_mut_ptr().offset(0),
                len - idx,
            );
            self.buffer.set_len(idx);
            other.buffer.set_len(len - idx);
        }
        self.inline_if_possible();
        other
    }

    /// Splits a string into two strings at the char index given.
    /// The first section of the split is stored in the original string,
    /// while the second section of the split is returned as a new string.
    pub fn split_off_at_char(&mut self, char_idx: usize) -> Self {
        debug_assert!(char_idx <= count_chars(self));
        let byte_idx = char_idx_to_byte_idx(self, char_idx);
        self.split_off(byte_idx)
    }

    #[inline(always)]
    pub fn shrink_to_fit(&mut self) {
        self.buffer.shrink_to_fit();
    }

    /// Returns whether the string has spilled out into a heap-allocated
    /// memory area.
    pub fn spilled(&self) -> bool {
        self.buffer.spilled()
    }

    #[inline(always)]
    pub unsafe fn as_mut_smallvec(&mut self) -> &mut SmallVec<BackingArray> {
        &mut self.buffer
    }

    #[inline(always)]
    unsafe fn insert_bytes(&mut self, idx: usize, bytes: &[u8]) {
        assert!(idx <= self.len());
        debug_assert!((self.len() + bytes.len()) <= MAX_BYTES);

        let len = self.len();
        let amt = bytes.len();
        self.buffer.reserve(amt);

        ptr::copy(
            self.buffer.as_ptr().offset(idx as isize),
            self.buffer.as_mut_ptr().offset((idx + amt) as isize),
            len - idx,
        );
        ptr::copy(
            bytes.as_ptr(),
            self.buffer.as_mut_ptr().offset(idx as isize),
            amt,
        );
        self.buffer.set_len(len + amt);
    }

    #[inline(always)]
    unsafe fn remove_bytes(&mut self, start: usize, end: usize) {
        assert!(start <= end);
        assert!(end <= self.len());
        let len = self.len();
        let amt = end - start;
        ptr::copy(
            self.buffer.as_ptr().offset(end as isize),
            self.buffer.as_mut_ptr().offset(start as isize),
            len - end,
        );
        self.buffer.set_len(len - amt);

        self.inline_if_possible();
    }

    /// Re-inlines the data if it's been heap allocated but can
    /// fit inline.
    #[inline(always)]
    fn inline_if_possible(&mut self) {
        if self.buffer.spilled() && (self.buffer.len() <= self.buffer.inline_size()) {
            self.buffer.shrink_to_fit();
        }
    }
}

impl std::cmp::PartialEq for NodeText {
    fn eq(&self, other: &Self) -> bool {
        let (s1, s2): (&str, &str) = (self, other);
        s1 == s2
    }
}

impl<'a> PartialEq<NodeText> for &'a str {
    fn eq(&self, other: &NodeText) -> bool {
        *self == (other as &str)
    }
}

impl<'a> PartialEq<&'a str> for NodeText {
    fn eq(&self, other: &&'a str) -> bool {
        (self as &str) == *other
    }
}

impl std::fmt::Display for NodeText {
    fn fmt(&self, fm: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        NodeText::deref(self).fmt(fm)
    }
}

impl std::fmt::Debug for NodeText {
    fn fmt(&self, fm: &mut std::fmt::Formatter) -> std::fmt::Result {
        NodeText::deref(self).fmt(fm)
    }
}

impl<'a> From<&'a str> for NodeText {
    fn from(s: &str) -> Self {
        Self::from_str(s)
    }
}

impl Deref for NodeText {
    type Target = str;

    fn deref(&self) -> &str {
        // NodeText's methods don't allow `buffer` to become invalid utf8,
        // so this is safe.
        unsafe { str::from_utf8_unchecked(self.buffer.as_ref()) }
    }
}

impl AsRef<str> for NodeText {
    fn as_ref(&self) -> &str {
        // NodeText's methods don't allow `buffer` to become invalid utf8,
        // so this is safe.
        unsafe { str::from_utf8_unchecked(self.buffer.as_ref()) }
    }
}

impl Borrow<str> for NodeText {
    fn borrow(&self) -> &str {
        // NodeText's methods don't allow `buffer` to become invalid utf8,
        // so this is safe.
        unsafe { str::from_utf8_unchecked(self.buffer.as_ref()) }
    }
}

//=======================================================================

/// Takes two `NodeText`s and mends the segment break between them, if any.
///
/// Note: this will leave one of the strings empty if the entire composite string
/// is one big grapheme.
pub(crate) fn fix_segment_seam(l: &mut NodeText, r: &mut NodeText) {
    // Early out, if there's nothing to do.
    if crlf::seam_is_break(l.as_bytes(), r.as_bytes()) {
        return;
    }

    // Find the nearest breaks around the seam.
    let l_split = crlf::prev_break(l.len(), l.as_bytes());
    let r_split = l.len() + crlf::next_break(0, r.as_bytes());

    // Find the new split position, if any.
    let new_split_pos = {
        let tot_len = l.len() + r.len();
        if l_split != 0 && (r_split == tot_len || l.len() > r.len()) {
            l_split
        } else {
            r_split
        }
    };

    // Move the bytes to create the new split
    if new_split_pos < l.len() {
        r.insert_str(0, &l[new_split_pos..]);
        l.truncate(new_split_pos);
    } else {
        let pos = new_split_pos - l.len();
        l.push_str(&r[..pos]);
        r.truncate_front(pos);
    }
}

//=======================================================================

/// The backing internal buffer for `NodeText`.
#[derive(Copy, Clone)]
pub(crate) struct BackingArray([u8; MAX_BYTES]);
unsafe impl Array for BackingArray {
    type Item = u8;
    fn size() -> usize {
        MAX_BYTES
    }
    fn ptr(&self) -> *const u8 {
        &self.0[0]
    }
    fn ptr_mut(&mut self) -> *mut u8 {
        &mut self.0[0]
    }
}

//=======================================================================

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

    #[test]
    fn remove_bytes_01() {
        let mut s = NodeText::new();
        s.push_str("Hello!");
        unsafe {
            s.remove_bytes(2, 4);
        }
        assert_eq!("Heo!", s);
    }
}
<|endoftext|>


<commit_before>pub const KB: usize = 1024;
pub const GB: usize = KB * 1024;
<commit_msg>Correct definition of gigabyte<commit_after>pub const KB: usize = 1024;
pub const MB: usize = KB * 1024;
pub const GB: usize = MB * 1024;
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::mem;

use sha1::Sha1;

use wasm_context::{
    FnTy,
    FunctionKind,
    FunctionIndex,
    TypeIndex,
    Import,
    Export,
    Context,
    Opcode
};

fn hash( string: &str ) -> String {
    let mut hasher = Sha1::new();
    hasher.update( string.as_bytes() );
    format!( "{}", hasher.digest() )
}

pub struct JsSnippet {
    pub name: String,
    pub code: String,
    pub ty: FnTy
}

impl JsSnippet {
    pub fn arg_count( &self ) -> usize {
        self.ty.params.len()
    }
}

struct Snippet {
    name: String,
    code: String,
    ty: FnTy,
    function_index: FunctionIndex
}

pub fn process_and_extract( ctx: &mut Context ) -> Vec< JsSnippet > {
    let mut shim_map: HashMap< FunctionIndex, TypeIndex > = HashMap::new();
    let mut snippet_offset_to_type_index = HashMap::new();
    let mut snippet_index_by_offset = HashMap::new();
    let mut snippet_index_by_hash: HashMap< String, usize > = HashMap::new();
    let mut snippets = Vec::new();

    for (&function_index, function) in &ctx.functions {
        if let &FunctionKind::Import { type_index, ref import, .. } = function {
            if import.module == "env" && import.field.starts_with( "__js_" ) {
                shim_map.insert( function_index, type_index );
            }
        }
    }

    for (_, function) in &ctx.functions {
        if let &FunctionKind::Definition { ref opcodes, .. } = function {
            for (index, opcode) in opcodes.iter().enumerate() {
                match opcode {
                    &Opcode::Call( function_index ) => {
                        if let Some( &type_index ) = shim_map.get( &function_index ) {
                            match opcodes[ index - 1 ] {
                                Opcode::I32Const( offset ) => {
                                    if let Some( previous_ty ) = snippet_offset_to_type_index.get( &offset ).cloned() {
                                        if type_index != previous_ty {
                                            panic!( "internal error: same snippet of JS (by offset) is used with two different shims; please report this!" );
                                        }
                                    }

                                    snippet_offset_to_type_index.insert( offset, type_index );
                                },
                                _ => panic!( "internal error: unexpected way of calling JS shims; please report this!" )
                            }
                        }
                    },
                    _ => {}
                }
            }
        }
    }

    for data in &ctx.data {
        if data.offset.len() != 2 {
            continue;
        }

        let (offset, type_index) = match (&data.offset[ 0 ], &data.offset[ 1 ]) {
            (&Opcode::I32Const( offset ), &Opcode::End) => {
                if let Some( &type_index ) = snippet_offset_to_type_index.get( &offset ) {
                    (offset, type_index)
                } else {
                    continue;
                }
            },
            _ => continue
        };

        let mut value_slice = data.value.as_slice();
        // Strip a trailing null if present.
        if value_slice.last().map( |&last_byte| last_byte == 0 ).unwrap_or( false ) {
            let len = value_slice.len();
            value_slice = &value_slice[ 0..len - 1 ];
        }

        let code = String::from_utf8( value_slice.to_owned() ).unwrap();
        let code_hash = hash( &code );

        let shim_ty = ctx.fn_ty_by_index( type_index ).unwrap();
        let ty = FnTy {
            params: shim_ty.params.iter().cloned().take( shim_ty.params.len() - 1 ).collect(),
            return_type: shim_ty.return_type.clone()
        };

        if let Some( &snippet_index ) = snippet_index_by_hash.get( &code_hash ) {
            let snippet: &Snippet = &snippets[ snippet_index ];
            if snippet.ty != ty {
                panic!( "internal error: same snippet of JS (by value) is used with two different shims; please report this!" );
            }

            snippet_index_by_offset.insert( offset, snippet_index );
        } else {
            let snippet = Snippet {
                name: format!( "__extjs_{}", code_hash ),
                code,
                ty,
                function_index: 0xFFFFFFFF
            };

            snippet_index_by_offset.insert( offset, snippets.len() );
            snippet_index_by_hash.insert( code_hash, snippets.len() );
            snippets.push( snippet );
        }
    }

    for snippet in &mut snippets {
        let type_index = ctx.get_or_add_fn_type( snippet.ty.clone() );
        let function_index = ctx.add_function( FunctionKind::Import {
            export: Export::none(),
            import: Import { module: "env".to_owned(), field: snippet.name.clone() },
            name: Some( snippet.name.clone() ),
            type_index
        });

        snippet.function_index = function_index;
    }

    for function_index in shim_map.keys() {
        ctx.functions.remove( function_index );
    }

    ctx.patch_code( |opcodes| {
        let should_process = opcodes.iter().any( |opcode| {
            match opcode {
                &Opcode::Call( function_index ) => shim_map.contains_key( &function_index ),
                _ => false
            }
        });

        if !should_process {
            return;
        }

        let mut new_opcodes = Vec::with_capacity( opcodes.len() );
        let mut old_opcodes = Vec::new();
        mem::swap( opcodes, &mut old_opcodes );

        for opcode in old_opcodes {
            match opcode {
                Opcode::Call( function_index ) if shim_map.contains_key( &function_index ) => {
                    // Pop the last argument which was a pointer to the code.
                    let offset = match new_opcodes.pop().unwrap() {
                        Opcode::I32Const( offset ) => offset,
                        _ => panic!()
                    };
                    let &snippet_index = snippet_index_by_offset.get( &offset ).unwrap();
                    let snippet = &snippets[ snippet_index ];
                    new_opcodes.push( Opcode::Call( snippet.function_index ) );
                }
                opcode => {
                    new_opcodes.push( opcode );
                }
            }
        }

        *opcodes = new_opcodes;
    });

    snippets.into_iter().map( |snippet| {
        JsSnippet {
            name: snippet.name,
            code: snippet.code,
            ty: snippet.ty
        }
    }).collect()
}
<commit_msg>Purge data entries containing JS snippets<commit_after>use std::collections::HashMap;
use std::mem;

use sha1::Sha1;

use wasm_context::{
    FnTy,
    FunctionKind,
    FunctionIndex,
    TypeIndex,
    Import,
    Export,
    Context,
    Opcode
};

fn hash( string: &str ) -> String {
    let mut hasher = Sha1::new();
    hasher.update( string.as_bytes() );
    format!( "{}", hasher.digest() )
}

pub struct JsSnippet {
    pub name: String,
    pub code: String,
    pub ty: FnTy
}

impl JsSnippet {
    pub fn arg_count( &self ) -> usize {
        self.ty.params.len()
    }
}

struct Snippet {
    name: String,
    code: String,
    ty: FnTy,
    function_index: FunctionIndex
}

pub fn process_and_extract( ctx: &mut Context ) -> Vec< JsSnippet > {
    let mut shim_map: HashMap< FunctionIndex, TypeIndex > = HashMap::new();
    let mut snippet_offset_to_type_index = HashMap::new();
    let mut snippet_index_by_offset = HashMap::new();
    let mut snippet_index_by_hash: HashMap< String, usize > = HashMap::new();
    let mut snippets = Vec::new();

    for (&function_index, function) in &ctx.functions {
        if let &FunctionKind::Import { type_index, ref import, .. } = function {
            if import.module == "env" && import.field.starts_with( "__js_" ) {
                shim_map.insert( function_index, type_index );
            }
        }
    }

    for (_, function) in &ctx.functions {
        if let &FunctionKind::Definition { ref opcodes, .. } = function {
            for (index, opcode) in opcodes.iter().enumerate() {
                match opcode {
                    &Opcode::Call( function_index ) => {
                        if let Some( &type_index ) = shim_map.get( &function_index ) {
                            match opcodes[ index - 1 ] {
                                Opcode::I32Const( offset ) => {
                                    if let Some( previous_ty ) = snippet_offset_to_type_index.get( &offset ).cloned() {
                                        if type_index != previous_ty {
                                            panic!( "internal error: same snippet of JS (by offset) is used with two different shims; please report this!" );
                                        }
                                    }

                                    snippet_offset_to_type_index.insert( offset, type_index );
                                },
                                _ => panic!( "internal error: unexpected way of calling JS shims; please report this!" )
                            }
                        }
                    },
                    _ => {}
                }
            }
        }
    }

    let mut data_entries = Vec::new();
    mem::swap( &mut data_entries, &mut ctx.data );

    data_entries.retain( |data| {
        if data.offset.len() != 2 {
            return true;
        }

        let (offset, type_index) = match (&data.offset[ 0 ], &data.offset[ 1 ]) {
            (&Opcode::I32Const( offset ), &Opcode::End) => {
                if let Some( &type_index ) = snippet_offset_to_type_index.get( &offset ) {
                    (offset, type_index)
                } else {
                    return true;
                }
            },
            _ => return true
        };

        let mut value_slice = data.value.as_slice();
        // Strip a trailing null if present.
        if value_slice.last().map( |&last_byte| last_byte == 0 ).unwrap_or( false ) {
            let len = value_slice.len();
            value_slice = &value_slice[ 0..len - 1 ];
        }

        let code = String::from_utf8( value_slice.to_owned() ).unwrap();
        let code_hash = hash( &code );

        let shim_ty = ctx.fn_ty_by_index( type_index ).unwrap();
        let ty = FnTy {
            params: shim_ty.params.iter().cloned().take( shim_ty.params.len() - 1 ).collect(),
            return_type: shim_ty.return_type.clone()
        };

        if let Some( &snippet_index ) = snippet_index_by_hash.get( &code_hash ) {
            let snippet: &Snippet = &snippets[ snippet_index ];
            if snippet.ty != ty {
                panic!( "internal error: same snippet of JS (by value) is used with two different shims; please report this!" );
            }

            snippet_index_by_offset.insert( offset, snippet_index );
        } else {
            let snippet = Snippet {
                name: format!( "__extjs_{}", code_hash ),
                code,
                ty,
                function_index: 0xFFFFFFFF
            };

            snippet_index_by_offset.insert( offset, snippets.len() );
            snippet_index_by_hash.insert( code_hash, snippets.len() );
            snippets.push( snippet );
        }

        return false;
    });

    ctx.data = data_entries;

    for snippet in &mut snippets {
        let type_index = ctx.get_or_add_fn_type( snippet.ty.clone() );
        let function_index = ctx.add_function( FunctionKind::Import {
            export: Export::none(),
            import: Import { module: "env".to_owned(), field: snippet.name.clone() },
            name: Some( snippet.name.clone() ),
            type_index
        });

        snippet.function_index = function_index;
    }

    for function_index in shim_map.keys() {
        ctx.functions.remove( function_index );
    }

    ctx.patch_code( |opcodes| {
        let should_process = opcodes.iter().any( |opcode| {
            match opcode {
                &Opcode::Call( function_index ) => shim_map.contains_key( &function_index ),
                _ => false
            }
        });

        if !should_process {
            return;
        }

        let mut new_opcodes = Vec::with_capacity( opcodes.len() );
        let mut old_opcodes = Vec::new();
        mem::swap( opcodes, &mut old_opcodes );

        for opcode in old_opcodes {
            match opcode {
                Opcode::Call( function_index ) if shim_map.contains_key( &function_index ) => {
                    // Pop the last argument which was a pointer to the code.
                    let offset = match new_opcodes.pop().unwrap() {
                        Opcode::I32Const( offset ) => offset,
                        _ => panic!()
                    };
                    let &snippet_index = snippet_index_by_offset.get( &offset ).unwrap();
                    let snippet = &snippets[ snippet_index ];
                    new_opcodes.push( Opcode::Call( snippet.function_index ) );
                }
                opcode => {
                    new_opcodes.push( opcode );
                }
            }
        }

        *opcodes = new_opcodes;
    });

    snippets.into_iter().map( |snippet| {
        JsSnippet {
            name: snippet.name,
            code: snippet.code,
            ty: snippet.ty
        }
    }).collect()
}
<|endoftext|>


<commit_before>extern crate user32;
extern crate winapi;
extern crate kernel32;
extern crate libc;
extern crate gdi32;

use std::ffi::OsStr;
use std::iter::once;
use std::os::windows::ffi::OsStrExt;
use std::mem;
use std::num::Wrapping;

use self::winapi::winuser::*;
use self::winapi::windef::*;
use self::winapi::minwindef::*;
use self::winapi::wingdi::*;
use self::winapi::winnt::*;
use self::winapi::xinput::*;
// Dynamic Linking XInput because reasons.  See the initialising code
type XInputGetStateType = extern "system" fn(user_index:DWORD, state: *mut XINPUT_STATE) -> DWORD;
extern "system" fn xinput_get_state_stub(_: DWORD, _: *mut XINPUT_STATE) -> DWORD {
    self::winapi::winerror::ERROR_DEVICE_NOT_CONNECTED
}
static mut XINPUT_GET_STATE_PTR: XInputGetStateType = xinput_get_state_stub;

type XInputSetStateType = extern "system" fn(user_index:DWORD, state: *mut XINPUT_VIBRATION) -> DWORD;
extern "system" fn xinput_set_state_stub(_: DWORD, _: *mut XINPUT_VIBRATION) -> DWORD {
    self::winapi::winerror::ERROR_DEVICE_NOT_CONNECTED
}
static mut XINPUT_SET_STATE_PTR: XInputSetStateType = xinput_set_state_stub;

struct Win32OffscreenBuffer {
    info: BITMAPINFO,
    bytes_per_pixel: i32,
    width: i32,
    height: i32,
    memory: LPVOID
}

struct WindowDimensions {
    width: i32,
    height: i32
}

static mut GLOBAL_RUNNING: bool = true;

static mut OFFSCREEN_BUFFER: Win32OffscreenBuffer = Win32OffscreenBuffer {
    info: BITMAPINFO {
        bmiHeader: BITMAPINFOHEADER {
            biSize: 0,
            biWidth: 0,
            biHeight: 0,
            biPlanes: 1,
            biBitCount: 32,
            biCompression: BI_RGB,
            biSizeImage: 0,
            biXPelsPerMeter: 0,
            biYPelsPerMeter: 0,
            biClrUsed: 0,
            biClrImportant: 0
        } ,
        bmiColors: []
    },
    bytes_per_pixel: 4,
    width: 0,
    height: 0,
    memory: 0 as LPVOID
};

macro_rules! cstr {
    ($str:expr) => ({
        use std::ffi::CString;
        CString::new($str).unwrap().as_ptr()
    });
}

macro_rules! wstr {
    ($str:expr) => ({
        use std::ffi::OsStr;
        use std::os::windows::ffi::OsStrExt;
        let wstr: Vec<u16> = OsStr::new($str)
                                 .encode_wide()
                                 .chain(Some(0).into_iter())
                                 .collect();
        wstr.as_ptr()
    });
}

unsafe fn win32_load_xinput() {
        //Version available on modern windows without DX SDK Install
        let mut xinput_module = kernel32::LoadLibraryW(wstr!("xinput1_4.dll"));

        if xinput_module == 0 as HMODULE {
            //Version available on old windows without DX SDK Install
            xinput_module = kernel32::LoadLibraryW(wstr!("xinput9_1_0.dll"));
        }

        if xinput_module != 0 as HMODULE {
            XINPUT_GET_STATE_PTR = mem::transmute::<FARPROC, XInputGetStateType>(kernel32::GetProcAddress(xinput_module, cstr!("XInputGetState")));
            XINPUT_SET_STATE_PTR = mem::transmute::<FARPROC, XInputSetStateType>(kernel32::GetProcAddress(xinput_module, cstr!("XInputSetState")));
        }
}

unsafe fn win32_get_window_dimensions (window_handle: HWND) -> WindowDimensions {
    let mut window_rect: RECT = mem::uninitialized();
    user32::GetClientRect(window_handle, &mut window_rect);
    WindowDimensions {
        width: window_rect.right - window_rect.left,
        height: window_rect.bottom - window_rect.top
    }
}

unsafe fn win32_resize_dib_section(buffer: &mut Win32OffscreenBuffer, width: i32, height: i32) -> () {
    buffer.width = width;
    buffer.height = height;
    buffer.info.bmiHeader.biWidth = width;
    buffer.info.bmiHeader.biHeight = -height; //Top-down coord

    let bitmap_memory_size = (width*height)*buffer.bytes_per_pixel;

    if buffer.memory != 0 as LPVOID {
        kernel32::VirtualFree(buffer.memory, 0 as u64, MEM_RELEASE);
    }

    buffer.memory = kernel32::VirtualAlloc(0 as LPVOID, bitmap_memory_size as u64, MEM_COMMIT, PAGE_READWRITE);

}

fn to_wide_string(str: &str) -> Vec<u16> {
    OsStr::new(str).encode_wide().chain(once(0)).collect()
}

unsafe fn draw_weird_gradient(buffer: &mut Win32OffscreenBuffer, x_offset: i16, y_offset: i16) {

    let width = buffer.width as i16;
    let height = buffer.height as i16;
    let bytes_per_pixel = buffer.bytes_per_pixel as i16;

    let pitch = width*bytes_per_pixel;
    let mut row: *mut u8 = buffer.memory as *mut u8;
    for y in 0..height {
        let mut pixel: *mut u32 = row as *mut u32;
        for x in 0..width {
            *pixel = ((x.wrapping_add(x_offset) as u8) << 0) as u32 + (((y.wrapping_add(-y_offset) as u8) as u32) << 8);
            pixel = pixel.offset(1);

        };
        row = row.offset(pitch as isize);
    };
}

unsafe fn win32_update_window(device_context: HDC, buffer: &mut Win32OffscreenBuffer, window_width: i32, window_height: i32) {
    gdi32::StretchDIBits(device_context,
        0, 0, window_width, window_height,
        0, 0, buffer.width, buffer.height,
        buffer.memory,
        &buffer.info,
        DIB_RGB_COLORS,
        SRCCOPY);
}

pub fn main() {
    unsafe {
        OFFSCREEN_BUFFER.info.bmiHeader.biSize = mem::size_of::<BITMAPINFOHEADER>() as u32;
        win32_resize_dib_section(&mut OFFSCREEN_BUFFER, 1280, 720);
        win32_load_xinput();
    }

    let window_class_name = to_wide_string("RustHeroWindowClass").as_ptr();
    let h_instance = unsafe {
        kernel32::GetModuleHandleW(0 as winapi::winnt::LPCWSTR)
    };

    let mut window = WNDCLASSW {
        style: CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
        lpfnWndProc: Some(winproc),
        cbClsExtra: 0,
        cbWndExtra: 0,
        hInstance: h_instance,
        hIcon: unsafe { user32::LoadIconW(h_instance, winapi::winuser::IDI_APPLICATION) },
        hCursor: unsafe { user32::LoadCursorW(h_instance, winapi::winuser::IDI_APPLICATION) },
        hbrBackground: 0 as HBRUSH,
        lpszMenuName: to_wide_string("RustHeroMenu").as_ptr(),
        lpszClassName: window_class_name
    };

    let ret = unsafe { //TODO: Can we use Options to get rid of all these unsafes?
        user32::RegisterClassW(&mut window)
    };

    if ret == 0 {
        println!("Registering the window class failed.");
        return
    }

    unsafe {
         let window_handle = user32::CreateWindowExW(
            0,
            window_class_name,
            to_wide_string("Rust Hero").as_ptr(),
            WS_VISIBLE|WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            0 as HWND,
            0 as HMENU,
            h_instance,
            0 as LPVOID
        );

        if window_handle.is_null() {
            println!("Failed to create window.");
            return;
        }

        let device_context = user32::GetDC(window_handle);

        let mut x_offset = 0;
        let mut y_offset = 0;
        let pan_speed = 10;

        while GLOBAL_RUNNING {
            let mut msg: MSG = mem::uninitialized();
            while user32::PeekMessageW(&mut msg, window_handle,0,0,PM_REMOVE) != 0 {
                user32::TranslateMessage(&mut msg);
                user32::DispatchMessageW(&mut msg);
            }

            for controller_index in 0..XUSER_MAX_COUNT {
                let mut controller_state = mem::uninitialized();
                let controller_found = XINPUT_GET_STATE_PTR(controller_index as DWORD, &mut controller_state);
                if controller_found == self::winapi::winerror::ERROR_SUCCESS {
                    let pad = controller_state.Gamepad;

                    let dpad_up = pad.wButtons & XINPUT_GAMEPAD_DPAD_UP;
                    let dpad_down = pad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN;
                    let dpad_left = pad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT;
                    let dpad_right = pad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT;
                    let a = pad.wButtons & XINPUT_GAMEPAD_A;
                    let b = pad.wButtons & XINPUT_GAMEPAD_B;
                    let x = pad.wButtons & XINPUT_GAMEPAD_X;
                    let y = pad.wButtons & XINPUT_GAMEPAD_Y;
                    let start = pad.wButtons & XINPUT_GAMEPAD_START;
                    let back = pad.wButtons & XINPUT_GAMEPAD_BACK;
                    let left_shoulder = pad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER;
                    let right_shoulder = pad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER;

                    let stick_x = pad.sThumbLX;
                    let stick_y = pad.sThumbLY;

                    if stick_x.abs() > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE { x_offset += stick_x >> 12; }
                    if stick_y.abs() > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE { y_offset += stick_y >> 12; }

                    //XINPUT_SET_STATE_PTR(controller_index, &mut XINPUT_VIBRATION { wLeftMotorSpeed: 60000, wRightMotorSpeed: 60000 });
                } else {
                    //TODO: Check if we care about this controller.
                }
            }

            // x += 1;
            // y += 1;
            draw_weird_gradient(&mut OFFSCREEN_BUFFER, x_offset, y_offset);

            let window_dimensions = win32_get_window_dimensions(window_handle);
            win32_update_window(device_context, &mut OFFSCREEN_BUFFER, window_dimensions.width, window_dimensions.height);
        }
    }
}

 pub unsafe extern "system" fn winproc(hwnd :HWND, msg :UINT, w_param :WPARAM, l_param :LPARAM) -> LRESULT {
    match msg {
        WM_SIZE => {  },
        WM_CLOSE => {  GLOBAL_RUNNING = false;  },
        WM_DESTROY => { GLOBAL_RUNNING = false; },
        WM_ACTIVATEAPP => { println!("WM_ACTIVATEAPP"); },
        WM_PAINT => {
            let mut paint: PAINTSTRUCT = mem::uninitialized();
            let hdc = user32::BeginPaint(hwnd, &mut paint);
            let window_dimensions = win32_get_window_dimensions(hwnd);
            win32_update_window(hdc, &mut OFFSCREEN_BUFFER, window_dimensions.width, window_dimensions.height);
            user32::EndPaint(hwnd, &paint);
        },
        WM_KEYDOWN | WM_KEYUP | WM_SYSKEYDOWN | WM_SYSKEYUP => {
            let vk_code = w_param;
            let was_down = (l_param & 1 << 30) != 0;
            let is_down = (l_param & 1 << 31) == 0;
            let alt_down = (l_param & 1 << 29) != 0;

            if vk_code == 'W' as u64 {
            }
            if vk_code == 'A' as u64 {
            }
            if vk_code == 'S' as u64 {
            }
            if vk_code == 'D' as u64 {
            }
            if vk_code == 'Q' as u64 {
            }
            if vk_code == VK_UP as u64 {
            }
            if vk_code == VK_DOWN as u64 {
            }
            if vk_code == VK_LEFT as u64 {
            }
            if vk_code == VK_RIGHT as u64 {
            }
            if vk_code == VK_ESCAPE as u64 {
                if is_down != was_down {
                    println!("ESCAPE");
                }
            }
            if vk_code == VK_SPACE as u64 {
                println!("\n");
            }
            if vk_code == VK_F4 as u64 && alt_down {
                GLOBAL_RUNNING = false;
             }

        },
        _ => { return user32::DefWindowProcW(hwnd, msg, w_param, l_param); }
    };
    0
}<commit_msg>Completed initialising dsound<commit_after>extern crate user32;
extern crate winapi;
extern crate kernel32;
extern crate libc;
extern crate gdi32;

use std::ffi::OsStr;
use std::iter::once;
use std::os::windows::ffi::OsStrExt;
use std::mem;
use std::ptr::null_mut;

use self::winapi::winuser::*;
use self::winapi::windef::*;
use self::winapi::minwindef::*;
use self::winapi::wingdi::*;
use self::winapi::winnt::*;
use self::winapi::xinput::*;
use self::winapi::dsound::*;
use self::winapi::unknwnbase::LPUNKNOWN;
use self::winapi::guiddef::LPCGUID;
use self::winapi::winerror::{HRESULT, SUCCEEDED};
use self::winapi::mmreg::{WAVEFORMATEX,WAVE_FORMAT_PCM};
use self::winapi::guiddef::GUID;

// Dynamic Linking XInput because reasons.  See the initialising code
type XInputGetStateType = extern "system" fn(user_index:DWORD, state: *mut XINPUT_STATE) -> DWORD;
extern "system" fn xinput_get_state_stub(_: DWORD, _: *mut XINPUT_STATE) -> DWORD {
    self::winapi::winerror::ERROR_DEVICE_NOT_CONNECTED
}
static mut XINPUT_GET_STATE_PTR: XInputGetStateType = xinput_get_state_stub;

type XInputSetStateType = extern "system" fn(user_index:DWORD, state: *mut XINPUT_VIBRATION) -> DWORD;
extern "system" fn xinput_set_state_stub(_: DWORD, _: *mut XINPUT_VIBRATION) -> DWORD {
    self::winapi::winerror::ERROR_DEVICE_NOT_CONNECTED
}
static mut XINPUT_SET_STATE_PTR: XInputSetStateType = xinput_set_state_stub;

type DirectSoundCreate = extern "system" fn(pcGuidDevice: LPCGUID, ppds: *mut LPDIRECTSOUND, pUnkOuter: LPUNKNOWN) -> HRESULT;

struct Win32OffscreenBuffer {
    info: BITMAPINFO,
    bytes_per_pixel: i32,
    width: i32,
    height: i32,
    memory: LPVOID
}

struct WindowDimensions {
    width: i32,
    height: i32
}

static mut GLOBAL_RUNNING: bool = true;

static mut OFFSCREEN_BUFFER: Win32OffscreenBuffer = Win32OffscreenBuffer {
    info: BITMAPINFO {
        bmiHeader: BITMAPINFOHEADER {
            biSize: 0,
            biWidth: 0,
            biHeight: 0,
            biPlanes: 1,
            biBitCount: 32,
            biCompression: BI_RGB,
            biSizeImage: 0,
            biXPelsPerMeter: 0,
            biYPelsPerMeter: 0,
            biClrUsed: 0,
            biClrImportant: 0
        } ,
        bmiColors: []
    },
    bytes_per_pixel: 4,
    width: 0,
    height: 0,
    memory: 0 as LPVOID
};

macro_rules! cstr {
    ($str:expr) => ({
        use std::ffi::CString;
        CString::new($str).unwrap().as_ptr()
    });
}

macro_rules! wstr {
    ($str:expr) => ({
        use std::ffi::OsStr;
        use std::os::windows::ffi::OsStrExt;
        let wstr: Vec<u16> = OsStr::new($str)
                                 .encode_wide()
                                 .chain(Some(0).into_iter())
                                 .collect();
        wstr.as_ptr()
    });
}

unsafe fn win32_load_xinput() {
    //Version available on modern windows without DX SDK Install
    let mut xinput_module = kernel32::LoadLibraryW(wstr!("xinput1_4.dll"));

    if xinput_module == 0 as HMODULE {
        //Version available on old windows without DX SDK Install
        xinput_module = kernel32::LoadLibraryW(wstr!("xinput9_1_0.dll"));
    }

    if xinput_module != 0 as HMODULE {
        XINPUT_GET_STATE_PTR = mem::transmute::<FARPROC, XInputGetStateType>(kernel32::GetProcAddress(xinput_module, cstr!("XInputGetState")));
        XINPUT_SET_STATE_PTR = mem::transmute::<FARPROC, XInputSetStateType>(kernel32::GetProcAddress(xinput_module, cstr!("XInputSetState")));
    }
}

unsafe fn win32_load_direct_sound(window_handle: HWND, samples_per_second: u32, buffer_bytes: u32) {
    let dsound_module = kernel32::LoadLibraryW(wstr!("dsound.dll"));

    if dsound_module != 0 as HMODULE {
        let direct_sound_create_ptr: DirectSoundCreate = mem::transmute::<FARPROC, DirectSoundCreate>(kernel32::GetProcAddress(dsound_module, cstr!("DirectSoundCreate")));
        let mut direct_sound: LPDIRECTSOUND = mem::uninitialized();
        if SUCCEEDED(direct_sound_create_ptr(0 as LPCGUID, &mut direct_sound, 0 as LPUNKNOWN)) {
            if SUCCEEDED((*direct_sound).SetCooperativeLevel(window_handle, DSSCL_PRIORITY)) != true {
                println!("Failed to set cooperative level.");
            }

            let buffer_description = DSBUFFERDESC {
                dwSize: mem::size_of::<DSBUFFERDESC>() as u32,
                dwFlags: DSBCAPS_PRIMARYBUFFER,
                dwBufferBytes: 0,
                dwReserved: 0,
                lpwfxFormat: null_mut(),
                guid3DAlgorithm: GUID {Data1: 0, Data2: 0, Data3: 0, Data4: [0;8] }
            };

            let mut primary_buffer: LPDIRECTSOUNDBUFFER = mem::uninitialized();
            if !SUCCEEDED((*direct_sound).CreateSoundBuffer(&buffer_description, &mut primary_buffer, 0 as LPUNKNOWN)) {
                println!("Failed to create primary buffer");
            }

            let mut wave_format: WAVEFORMATEX = mem::zeroed();
            wave_format.wFormatTag      = WAVE_FORMAT_PCM;
            wave_format.nChannels       = 2;
            wave_format.nSamplesPerSec  = samples_per_second;
            wave_format.wBitsPerSample  = 16;
            wave_format.nBlockAlign     = (wave_format.nChannels * wave_format.wBitsPerSample) / 8;
            wave_format.nAvgBytesPerSec = wave_format.nSamplesPerSec * wave_format.nBlockAlign as DWORD;
            wave_format.cbSize          = 0;

            if !SUCCEEDED((*primary_buffer).SetFormat(&wave_format)) {
                println!("Failed to set format of primary buffer");
            }

            let buffer_description = DSBUFFERDESC {
                dwSize: mem::size_of::<DSBUFFERDESC>() as u32,
                dwFlags: DSBCAPS_GETCURRENTPOSITION2,
                dwBufferBytes: buffer_bytes,
                dwReserved: 0,
                lpwfxFormat: &mut wave_format,
                guid3DAlgorithm: GUID {Data1: 0, Data2: 0, Data3: 0, Data4: [0;8] }
            };

            let mut secondary_buffer = mem::uninitialized();
            if !SUCCEEDED((*direct_sound).CreateSoundBuffer(&buffer_description, &mut secondary_buffer, null_mut())) {
                println!("Failed to create secondary buffer");
            }
        }
    }
}

unsafe fn win32_get_window_dimensions (window_handle: HWND) -> WindowDimensions {
    let mut window_rect: RECT = mem::uninitialized();
    user32::GetClientRect(window_handle, &mut window_rect);
    WindowDimensions {
        width: window_rect.right - window_rect.left,
        height: window_rect.bottom - window_rect.top
    }
}

unsafe fn win32_resize_dib_section(buffer: &mut Win32OffscreenBuffer, width: i32, height: i32) -> () {
    buffer.width = width;
    buffer.height = height;
    buffer.info.bmiHeader.biWidth = width;
    buffer.info.bmiHeader.biHeight = -height; //Top-down coord

    let bitmap_memory_size = (width*height)*buffer.bytes_per_pixel;

    if buffer.memory != 0 as LPVOID {
        kernel32::VirtualFree(buffer.memory, 0 as u64, MEM_RELEASE);
    }

    buffer.memory = kernel32::VirtualAlloc(0 as LPVOID, bitmap_memory_size as u64, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
}

fn to_wide_string(str: &str) -> Vec<u16> {
    OsStr::new(str).encode_wide().chain(once(0)).collect()
}

unsafe fn draw_weird_gradient(buffer: &mut Win32OffscreenBuffer, x_offset: i16, y_offset: i16) {

    let width = buffer.width as i16;
    let height = buffer.height as i16;
    let bytes_per_pixel = buffer.bytes_per_pixel as i16;

    let pitch = width*bytes_per_pixel;
    let mut row: *mut u8 = buffer.memory as *mut u8;
    for y in 0..height {
        let mut pixel: *mut u32 = row as *mut u32;
        for x in 0..width {
            *pixel = ((x.wrapping_add(x_offset) as u8) << 0) as u32 + (((y.wrapping_add(-y_offset) as u8) as u32) << 8);
            pixel = pixel.offset(1);

        };
        row = row.offset(pitch as isize);
    };
}

unsafe fn win32_update_window(device_context: HDC, buffer: &mut Win32OffscreenBuffer, window_width: i32, window_height: i32) {
    gdi32::StretchDIBits(device_context,
        0, 0, window_width, window_height,
        0, 0, buffer.width, buffer.height,
        buffer.memory,
        &buffer.info,
        DIB_RGB_COLORS,
        SRCCOPY);
}

pub fn main() {
    unsafe {
        OFFSCREEN_BUFFER.info.bmiHeader.biSize = mem::size_of::<BITMAPINFOHEADER>() as u32;
        win32_resize_dib_section(&mut OFFSCREEN_BUFFER, 1280, 720);
        win32_load_xinput();
    }

    let window_class_name = to_wide_string("RustHeroWindowClass").as_ptr();
    let h_instance = unsafe {
        kernel32::GetModuleHandleW(0 as winapi::winnt::LPCWSTR)
    };

    let mut window = WNDCLASSW {
        style: CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
        lpfnWndProc: Some(winproc),
        cbClsExtra: 0,
        cbWndExtra: 0,
        hInstance: h_instance,
        hIcon: unsafe { user32::LoadIconW(h_instance, winapi::winuser::IDI_APPLICATION) },
        hCursor: unsafe { user32::LoadCursorW(h_instance, winapi::winuser::IDI_APPLICATION) },
        hbrBackground: 0 as HBRUSH,
        lpszMenuName: to_wide_string("RustHeroMenu").as_ptr(),
        lpszClassName: window_class_name
    };

    let ret = unsafe { //TODO: Can we use Options to get rid of all these unsafes?
        user32::RegisterClassW(&mut window)
    };

    if ret == 0 {
        println!("Registering the window class failed.");
        return
    }

    unsafe {
         let window_handle = user32::CreateWindowExW(
            0,
            window_class_name,
            to_wide_string("Rust Hero").as_ptr(),
            WS_VISIBLE|WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            0 as HWND,
            0 as HMENU,
            h_instance,
            0 as LPVOID
        );

        if window_handle.is_null() {
            println!("Failed to create window.");
            return;
        }

        win32_load_direct_sound(window_handle, 48000, 48000 * 2 *2);  //casey set buffer size to 48000*sizeof(int16)*2???
        let device_context = user32::GetDC(window_handle);

        let mut x_offset = 0;
        let mut y_offset = 0;
        //let pan_speed = 10;

        while GLOBAL_RUNNING {
            let mut msg: MSG = mem::uninitialized();
            while user32::PeekMessageW(&mut msg, window_handle,0,0,PM_REMOVE) != 0 {
                user32::TranslateMessage(&mut msg);
                user32::DispatchMessageW(&mut msg);
            }

            for controller_index in 0..XUSER_MAX_COUNT {
                let mut controller_state = mem::uninitialized();
                let controller_found = XINPUT_GET_STATE_PTR(controller_index as DWORD, &mut controller_state);
                if controller_found == self::winapi::winerror::ERROR_SUCCESS {
                    let pad = controller_state.Gamepad;

                    // let dpad_up = pad.wButtons & XINPUT_GAMEPAD_DPAD_UP;
                    // let dpad_down = pad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN;
                    // let dpad_left = pad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT;
                    // let dpad_right = pad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT;
                    // let a = pad.wButtons & XINPUT_GAMEPAD_A;
                    // let b = pad.wButtons & XINPUT_GAMEPAD_B;
                    // let x = pad.wButtons & XINPUT_GAMEPAD_X;
                    // let y = pad.wButtons & XINPUT_GAMEPAD_Y;
                    // let start = pad.wButtons & XINPUT_GAMEPAD_START;
                    // let back = pad.wButtons & XINPUT_GAMEPAD_BACK;
                    // let left_shoulder = pad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER;
                    // let right_shoulder = pad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER;

                    let stick_x = pad.sThumbLX;
                    let stick_y = pad.sThumbLY;

                    if stick_x.abs() > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE { x_offset += stick_x >> 12; }
                    if stick_y.abs() > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE { y_offset += stick_y >> 12; }

                    //XINPUT_SET_STATE_PTR(controller_index, &mut XINPUT_VIBRATION { wLeftMotorSpeed: 60000, wRightMotorSpeed: 60000 });
                } else {
                    //TODO: Check if we care about this controller.
                }
            }

            // x += 1;
            // y += 1;
            draw_weird_gradient(&mut OFFSCREEN_BUFFER, x_offset, y_offset);

            let window_dimensions = win32_get_window_dimensions(window_handle);
            win32_update_window(device_context, &mut OFFSCREEN_BUFFER, window_dimensions.width, window_dimensions.height);
        }
    }
}

 pub unsafe extern "system" fn winproc(hwnd :HWND, msg :UINT, w_param :WPARAM, l_param :LPARAM) -> LRESULT {
    match msg {
        WM_SIZE => {  },
        WM_CLOSE => {  GLOBAL_RUNNING = false;  },
        WM_DESTROY => { GLOBAL_RUNNING = false; },
        WM_ACTIVATEAPP => { println!("WM_ACTIVATEAPP"); },
        WM_PAINT => {
            let mut paint: PAINTSTRUCT = mem::uninitialized();
            let hdc = user32::BeginPaint(hwnd, &mut paint);
            let window_dimensions = win32_get_window_dimensions(hwnd);
            win32_update_window(hdc, &mut OFFSCREEN_BUFFER, window_dimensions.width, window_dimensions.height);
            user32::EndPaint(hwnd, &paint);
        },
        WM_KEYDOWN | WM_KEYUP | WM_SYSKEYDOWN | WM_SYSKEYUP => {
            let vk_code = w_param;
            let was_down = (l_param & 1 << 30) != 0;
            let is_down = (l_param & 1 << 31) == 0;
            let alt_down = (l_param & 1 << 29) != 0;

            if vk_code == 'W' as u64 {
            }
            if vk_code == 'A' as u64 {
            }
            if vk_code == 'S' as u64 {
            }
            if vk_code == 'D' as u64 {
            }
            if vk_code == 'Q' as u64 {
            }
            if vk_code == VK_UP as u64 {
            }
            if vk_code == VK_DOWN as u64 {
            }
            if vk_code == VK_LEFT as u64 {
            }
            if vk_code == VK_RIGHT as u64 {
            }
            if vk_code == VK_ESCAPE as u64 {
                if is_down != was_down {
                    println!("ESCAPE");
                }
            }
            if vk_code == VK_SPACE as u64 {
                println!("\n");
            }
            if vk_code == VK_F4 as u64 && alt_down {
                GLOBAL_RUNNING = false;
             }

        },
        _ => { return user32::DefWindowProcW(hwnd, msg, w_param, l_param); }
    };
    0
}<|endoftext|>


<commit_before>use std::collections::HashMap;

pub type Id = u32;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Bounds {
    x: i32,
    y: i32,
    width: i32,
    height: i32,
}
impl Bounds {
    pub fn intersects(&self, other: &Self) -> bool {
        ((self.x - other.x).abs() * 2 < (self.width + other.width)) &&
            ((self.y - other.y).abs() * 2 < (self.height + other.height))
    }
    pub fn contains(&self, other: &Self) -> bool {
        other.x - other.width / 2 >= self.x - self.width / 2 &&
            other.y - other.height / 2 >= self.y - self.height / 2 &&
            other.x + other.width / 2 <= self.x + self.width / 2 &&
            other.y + other.height / 2 <= self.y + self.height / 2
    }
}

pub struct World {
    width: i32,
    height: i32,
    entities: HashMap<Id, Bounds>,
}

impl World {
    pub fn new(width: i32, height: i32) -> Self {
        World {
            width,
            height,
            entities: HashMap::new(),
        }
    }
    pub fn insert(&mut self, id: Id, bounds: Bounds) -> Option<Bounds> {
        assert!(
            bounds.x + bounds.width / 2 > 0 && bounds.y + bounds.height / 2 > 0 &&
                bounds.x - bounds.width / 2 < self.width &&
                bounds.y - bounds.height / 2 < self.height
        );
        self.entities.insert(id, bounds)
    }
    pub fn remove(&mut self, id: Id) -> Option<Bounds> {
        self.entities.remove(&id)
    }
    pub fn query_intersects<T>(&self, bounds: &Bounds, mut cb: T)
    where
        T: FnMut(Id, &Bounds),
    {
        for (id, entity) in &self.entities {
            if entity.intersects(bounds) {
                cb(*id, entity);
            }
        }
    }
}

#[test]
fn intersects() {
    let a = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    let b = Bounds {
        x: 5,
        y: 5,
        width: 10,
        height: 10,
    };
    assert!(a.intersects(&b));
}

#[test]
fn doesnt_intersect() {
    let a = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    let b = Bounds {
        x: 50,
        y: 50,
        width: 10,
        height: 10,
    };
    assert!(!a.intersects(&b));
}

#[test]
fn doesnt_intersect_edge() {
    let a = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    let b = Bounds {
        x: 15,
        y: 0,
        width: 10,
        height: 10,
    };
    assert!(!a.intersects(&b));
}

#[test]
fn contains() {
    let a = Bounds {
        x: 0,
        y: 0,
        width: 100,
        height: 100,
    };
    let b = Bounds {
        x: 2,
        y: 2,
        width: 10,
        height: 10,
    };
    assert!(a.contains(&b));
}

#[test]
fn doesnt_contain() {
    let a = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    let b = Bounds {
        x: 50,
        y: 50,
        width: 10,
        height: 10,
    };
    assert!(!a.contains(&b));
}

#[test]
fn doesnt_contain_when_intersecting() {
    let a = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    let b = Bounds {
        x: 5,
        y: 5,
        width: 10,
        height: 10,
    };
    assert!(!a.contains(&b));
}

#[test]
fn contains_edge() {
    let a = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    let b = Bounds {
        x: 10,
        y: 10,
        width: 0,
        height: 0,
    };
    assert!(!a.contains(&b));
}

#[test]
fn contains_self() {
    let a = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    assert!(a.contains(&a));
}

#[test]
fn init() {
    World::new(1000, 1000);
}

#[test]
fn insert_new() {
    let mut world = World::new(1000, 1000);
    let bounds = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    let old = world.insert(1, bounds);
    assert!(old.is_none());
}

#[test]
#[should_panic]
fn insert_too_low() {
    let mut world = World::new(1000, 1000);
    let bounds = Bounds {
        x: -10,
        y: -10,
        width: 1,
        height: 1,
    };
    world.insert(1, bounds);
}

#[test]
#[should_panic]
fn insert_too_low_edge() {
    let mut world = World::new(1000, 1000);
    let bounds = Bounds {
        x: -10,
        y: 0,
        width: 5,
        height: 5,
    };
    world.insert(1, bounds);
}

#[test]
#[should_panic]
fn insert_too_high() {
    let mut world = World::new(1000, 1000);
    let bounds = Bounds {
        x: 2000,
        y: 2000,
        width: 1,
        height: 1,
    };
    world.insert(1, bounds);
}

#[test]
#[should_panic]
fn insert_too_high_edge() {
    let mut world = World::new(1000, 1000);
    let bounds = Bounds {
        x: 0,
        y: 1010,
        width: 1,
        height: 5,
    };
    world.insert(1, bounds);
}

#[test]
fn insert_existing() {
    let mut world = World::new(1000, 1000);
    let id = 1;
    let bounds_a = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    let old = world.insert(id, bounds_a.clone());
    assert!(old.is_none());
    let bounds_b = Bounds {
        x: 1,
        y: 1,
        width: 10,
        height: 10,
    };
    let old = world.insert(id, bounds_b);
    assert_eq!(bounds_a, old.unwrap())
}

#[test]
fn remove() {
    let mut world = World::new(1000, 1000);
    let id = 1;
    let bounds = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    world.insert(id, bounds.clone());
    let removed_bounds = world.remove(id);
    assert_eq!(bounds, removed_bounds.unwrap());
    let old = world.insert(id, bounds);
    assert!(old.is_none());
}

#[test]
fn remove_nonexistant() {
    let mut world = World::new(1000, 1000);
    let bounds = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    world.insert(1, bounds);
    let removed = world.remove(2);
    assert!(removed.is_none())
}

#[test]
fn remove_empty() {
    let mut world = World::new(1000, 1000);
    let removed = world.remove(1);
    assert!(removed.is_none())
}

#[test]
fn remove_twice() {
    let mut world = World::new(1000, 1000);
    let id = 1;
    let bounds = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    world.insert(id, bounds.clone());
    let removed = world.remove(id);
    assert_eq!(bounds, removed.unwrap());
    let removed = world.remove(id);
    assert!(removed.is_none());
}

#[test]
fn no_collisions() {
    let mut world = World::new(1000, 1000);
    let id = 1;
    let bounds_a = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    world.insert(id, bounds_a.clone());
    let bounds_b = Bounds {
        x: 40,
        y: 40,
        width: 10,
        height: 10,
    };
    world.query_intersects(&bounds_b, |_, _| panic!());
}

#[test]
fn one_collision() {
    let mut world = World::new(1000, 1000);
    let id = 1;
    let bounds_a = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    world.insert(id, bounds_a.clone());
    let bounds_b = Bounds {
        x: 5,
        y: 5,
        width: 10,
        height: 10,
    };
    let mut collisions = Vec::new();
    world.query_intersects(
        &bounds_b,
        |id, bounds| collisions.push((id, bounds.clone())),
    );
    assert_eq!(1, collisions.len());
    let &(coll_id, ref coll_bounds) = collisions.first().unwrap();
    assert_eq!(id, coll_id);
    assert_eq!(bounds_a, *coll_bounds);
}
<commit_msg>Core: Add unit test<commit_after>use std::collections::HashMap;

pub type Id = u32;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Bounds {
    x: i32,
    y: i32,
    width: i32,
    height: i32,
}
impl Bounds {
    pub fn intersects(&self, other: &Self) -> bool {
        ((self.x - other.x).abs() * 2 < (self.width + other.width)) &&
            ((self.y - other.y).abs() * 2 < (self.height + other.height))
    }
    pub fn contains(&self, other: &Self) -> bool {
        other.x - other.width / 2 >= self.x - self.width / 2 &&
            other.y - other.height / 2 >= self.y - self.height / 2 &&
            other.x + other.width / 2 <= self.x + self.width / 2 &&
            other.y + other.height / 2 <= self.y + self.height / 2
    }
}

pub struct World {
    width: i32,
    height: i32,
    entities: HashMap<Id, Bounds>,
}

impl World {
    pub fn new(width: i32, height: i32) -> Self {
        World {
            width,
            height,
            entities: HashMap::new(),
        }
    }
    pub fn insert(&mut self, id: Id, bounds: Bounds) -> Option<Bounds> {
        assert!(
            bounds.x + bounds.width / 2 > 0 && bounds.y + bounds.height / 2 > 0 &&
                bounds.x - bounds.width / 2 < self.width &&
                bounds.y - bounds.height / 2 < self.height
        );
        self.entities.insert(id, bounds)
    }
    pub fn remove(&mut self, id: Id) -> Option<Bounds> {
        self.entities.remove(&id)
    }
    pub fn query_intersects<T>(&self, bounds: &Bounds, mut cb: T)
    where
        T: FnMut(Id, &Bounds),
    {
        for (id, entity) in &self.entities {
            if entity.intersects(bounds) {
                cb(*id, entity);
            }
        }
    }
    pub fn query_contains<T>(&self, bounds: &Bounds, mut cb: T)
        where
            T: FnMut(Id, &Bounds),
    {
        for (id, entity) in &self.entities {
            if entity.contains(bounds) {
                cb(*id, entity);
            }
        }
    }
}

#[test]
fn intersects() {
    let a = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    let b = Bounds {
        x: 5,
        y: 5,
        width: 10,
        height: 10,
    };
    assert!(a.intersects(&b));
}

#[test]
fn doesnt_intersect() {
    let a = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    let b = Bounds {
        x: 50,
        y: 50,
        width: 10,
        height: 10,
    };
    assert!(!a.intersects(&b));
}

#[test]
fn doesnt_intersect_edge() {
    let a = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    let b = Bounds {
        x: 15,
        y: 0,
        width: 10,
        height: 10,
    };
    assert!(!a.intersects(&b));
}

#[test]
fn contains() {
    let a = Bounds {
        x: 0,
        y: 0,
        width: 100,
        height: 100,
    };
    let b = Bounds {
        x: 2,
        y: 2,
        width: 10,
        height: 10,
    };
    assert!(a.contains(&b));
}

#[test]
fn doesnt_contain() {
    let a = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    let b = Bounds {
        x: 50,
        y: 50,
        width: 10,
        height: 10,
    };
    assert!(!a.contains(&b));
}

#[test]
fn doesnt_contain_when_intersecting() {
    let a = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    let b = Bounds {
        x: 5,
        y: 5,
        width: 10,
        height: 10,
    };
    assert!(!a.contains(&b));
}

#[test]
fn contains_edge() {
    let a = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    let b = Bounds {
        x: 10,
        y: 10,
        width: 0,
        height: 0,
    };
    assert!(!a.contains(&b));
}

#[test]
fn contains_self() {
    let a = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    assert!(a.contains(&a));
}

#[test]
fn init() {
    World::new(1000, 1000);
}

#[test]
fn insert_new() {
    let mut world = World::new(1000, 1000);
    let bounds = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    let old = world.insert(1, bounds);
    assert!(old.is_none());
}

#[test]
#[should_panic]
fn insert_too_low() {
    let mut world = World::new(1000, 1000);
    let bounds = Bounds {
        x: -10,
        y: -10,
        width: 1,
        height: 1,
    };
    world.insert(1, bounds);
}

#[test]
#[should_panic]
fn insert_too_low_edge() {
    let mut world = World::new(1000, 1000);
    let bounds = Bounds {
        x: -10,
        y: 0,
        width: 5,
        height: 5,
    };
    world.insert(1, bounds);
}

#[test]
#[should_panic]
fn insert_too_high() {
    let mut world = World::new(1000, 1000);
    let bounds = Bounds {
        x: 2000,
        y: 2000,
        width: 1,
        height: 1,
    };
    world.insert(1, bounds);
}

#[test]
#[should_panic]
fn insert_too_high_edge() {
    let mut world = World::new(1000, 1000);
    let bounds = Bounds {
        x: 0,
        y: 1010,
        width: 1,
        height: 5,
    };
    world.insert(1, bounds);
}

#[test]
fn insert_existing() {
    let mut world = World::new(1000, 1000);
    let id = 1;
    let bounds_a = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    let old = world.insert(id, bounds_a.clone());
    assert!(old.is_none());
    let bounds_b = Bounds {
        x: 1,
        y: 1,
        width: 10,
        height: 10,
    };
    let old = world.insert(id, bounds_b);
    assert_eq!(bounds_a, old.unwrap())
}

#[test]
fn remove() {
    let mut world = World::new(1000, 1000);
    let id = 1;
    let bounds = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    world.insert(id, bounds.clone());
    let removed_bounds = world.remove(id);
    assert_eq!(bounds, removed_bounds.unwrap());
    let old = world.insert(id, bounds);
    assert!(old.is_none());
}

#[test]
fn remove_nonexistant() {
    let mut world = World::new(1000, 1000);
    let bounds = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    world.insert(1, bounds);
    let removed = world.remove(2);
    assert!(removed.is_none())
}

#[test]
fn remove_empty() {
    let mut world = World::new(1000, 1000);
    let removed = world.remove(1);
    assert!(removed.is_none())
}

#[test]
fn remove_twice() {
    let mut world = World::new(1000, 1000);
    let id = 1;
    let bounds = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    world.insert(id, bounds.clone());
    let removed = world.remove(id);
    assert_eq!(bounds, removed.unwrap());
    let removed = world.remove(id);
    assert!(removed.is_none());
}

#[test]
fn no_collisions() {
    let mut world = World::new(1000, 1000);
    let id = 1;
    let bounds_a = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    world.insert(id, bounds_a.clone());
    let bounds_b = Bounds {
        x: 40,
        y: 40,
        width: 10,
        height: 10,
    };
    world.query_intersects(&bounds_b, |_, _| panic!());
}

#[test]
fn one_collision() {
    let mut world = World::new(1000, 1000);
    let id = 1;
    let bounds_a = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    world.insert(id, bounds_a.clone());
    let bounds_b = Bounds {
        x: 5,
        y: 5,
        width: 10,
        height: 10,
    };
    let mut collisions = Vec::new();
    world.query_intersects(
        &bounds_b,
        |id, bounds| collisions.push((id, bounds.clone())),
    );
    assert_eq!(1, collisions.len());
    let &(coll_id, ref coll_bounds) = collisions.first().unwrap();
    assert_eq!(id, coll_id);
    assert_eq!(bounds_a, *coll_bounds);
}

#[test]
fn multiple_collision() {
    let mut world = World::new(1000, 1000);
    let id_a = 1;
    let bounds_a = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    world.insert(id_a, bounds_a.clone());
    let id_b = 2;
    let bounds_b = Bounds {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    world.insert(id_b, bounds_b.clone());
    let bounds_c = Bounds {
        x: 5,
        y: 5,
        width: 10,
        height: 10,
    };
    let mut collisions = Vec::new();
    world.query_intersects(
        &bounds_c,
        |id, bounds| collisions.push((id, bounds.clone())),
    );
    assert_eq!(2, collisions.len());
    let (coll_id, ref coll_bounds) = collisions[0];
    let first_is_a = id_a == coll_id;
    if first_is_a {
        assert_eq!(id_a, coll_id);
        assert_eq!(bounds_a, *coll_bounds);
    } else {
        assert_eq!(id_b, coll_id);
        assert_eq!(bounds_b, *coll_bounds);
    }
    let (coll_id, ref coll_bounds) = collisions[1];
    if first_is_a {
        assert_eq!(id_b, coll_id);
        assert_eq!(bounds_b, *coll_bounds);
    } else {
        assert_eq!(id_a, coll_id);
        assert_eq!(bounds_a, *coll_bounds);
    }
}

<|endoftext|>


<commit_before>use std::env;
use std::error::Error;
use std::fs::File;
use std::io::{BufRead, BufReader, BufWriter, Write};
use std::path::{Path, PathBuf};

fn main() -> Result<(), Box<dyn Error>> {
    println!("cargo:rerun-if-changed=colors.csv");
    let path = Path::new(&env::var("OUT_DIR").unwrap()).join("colors.rs");
    let mut file = BufWriter::new(File::create(&path).unwrap());

    let rdr = BufReader::new(File::open(
        PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()).join("colors.txt"),
    )?);

    let mut map = phf_codegen::Map::new();
    let mut recs: Vec<(String, String)> = Vec::new();

    for result in rdr.lines() {
        let record = result?;
        let record = record.split("//").next().unwrap().trim();
        if record.is_empty() {
            continue;
        }
        let mut record = record.split_whitespace();
        let id = record.next().unwrap().to_owned();
        let hex = record.next().unwrap().to_owned();
        let clean_hex = hex.trim_start_matches('#');
        let color = match clean_hex.len() {
            3 => {
                let d = match u32::from_str_radix(&clean_hex, 16) {
                    Ok(x) => x,
                    Err(_) => 0,
                };

                let mut r = (d & 0xF) << 4;
                let mut g = ((d >> 4) & 0xF) << 4;
                let mut b = ((d >> 8) & 0xF) << 4;
                r |= r >> 4;
                g |= g >> 4;
                b |= b >> 4;

                format!("Color::rgb({}, {}, {})", r, g, b)
            }
            6 => {
                let x = match u32::from_str_radix(&clean_hex, 16) {
                    Ok(x) => x,
                    Err(_) => 0,
                };

                format!(
                    "Color::rgb({}, {}, {})",
                    ((x >> 16) & 0xFF) as u8,
                    ((x >> 8) & 0xFF) as u8,
                    (x & 0xFF) as u8
                )
            }
            _ => panic!(""),
        };
        recs.push((id, color));
    }

    for rec in recs.iter() {
        map.entry(&*rec.0, &rec.1);
    }

    map.entry("transparent", "Color::rgba(0, 0, 0, 0)");

    writeln!(
        &mut file,
        "static COLORS: phf::Map<&'static str, Color> = \n{};\n",
        map.build()
    )
    .unwrap();

    Ok(())
}
<commit_msg>Fix utils build script<commit_after>use std::env;
use std::error::Error;
use std::fs::File;
use std::io::{BufRead, BufReader, BufWriter, Write};
use std::path::{Path, PathBuf};

fn main() -> Result<(), Box<dyn Error>> {
    println!("cargo:rerun-if-changed=colors.txt");
    let path = Path::new(&env::var("OUT_DIR").unwrap()).join("colors.rs");
    let mut file = BufWriter::new(File::create(&path).unwrap());

    let rdr = BufReader::new(File::open(
        PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()).join("colors.txt"),
    )?);

    let mut map = phf_codegen::Map::new();
    let mut recs: Vec<(String, String)> = Vec::new();

    for result in rdr.lines() {
        let record = result?;
        let record = record.split("//").next().unwrap().trim();
        if record.is_empty() {
            continue;
        }
        let mut record = record.split_whitespace();
        let id = record.next().unwrap().to_owned();
        let hex = record.next().unwrap().to_owned();
        let clean_hex = hex.trim_start_matches('#');
        let color = match clean_hex.len() {
            3 => {
                let d = match u32::from_str_radix(&clean_hex, 16) {
                    Ok(x) => x,
                    Err(_) => 0,
                };

                let mut r = (d & 0xF) << 4;
                let mut g = ((d >> 4) & 0xF) << 4;
                let mut b = ((d >> 8) & 0xF) << 4;
                r |= r >> 4;
                g |= g >> 4;
                b |= b >> 4;

                format!("Color::rgb({}, {}, {})", r, g, b)
            }
            6 => {
                let x = match u32::from_str_radix(&clean_hex, 16) {
                    Ok(x) => x,
                    Err(_) => 0,
                };

                format!(
                    "Color::rgb({}, {}, {})",
                    ((x >> 16) & 0xFF) as u8,
                    ((x >> 8) & 0xFF) as u8,
                    (x & 0xFF) as u8
                )
            }
            _ => panic!(""),
        };
        recs.push((id, color));
    }

    for rec in recs.iter() {
        map.entry(&*rec.0, &rec.1);
    }

    map.entry("transparent", "Color::rgba(0, 0, 0, 0)");

    writeln!(
        &mut file,
        "static COLORS: phf::Map<&'static str, Color> = \n{};\n",
        map.build()
    )
    .unwrap();

    Ok(())
}
<|endoftext|>