<commit_before>///! Inline of `https://github.com/bltavares/atomic-shim`

#[cfg(not(any(
    target_arch = "mips",
    target_arch = "powerpc",
    feature = "mutex"
)))]
pub use std::sync::atomic::{AtomicI64, AtomicU64};
#[cfg(any(target_arch = "mips", target_arch = "powerpc", feature = "mutex"))]
mod shim {
    use crossbeam_utils::sync::ShardedLock;
    use std::sync::atomic::Ordering;

    #[derive(Debug, Default)]
    pub struct AtomicU64 {
        value: ShardedLock<u64>,
    }

    impl AtomicU64 {
        pub fn new(v: u64) -> Self {
            Self { value: ShardedLock::new(v) }
        }

        #[allow(dead_code)]
        pub fn get_mut(&mut self) -> &mut u64 {
            self.value.get_mut().unwrap()
        }

        #[allow(dead_code)]
        pub fn into_inner(self) -> u64 {
            self.value.into_inner().unwrap()
        }

        #[allow(dead_code)]
        pub fn load(&self, _: Ordering) -> u64 {
            *self.value.read().unwrap()
        }

        #[allow(dead_code)]
        pub fn store(&self, value: u64, _: Ordering) {
            let mut lock = self.value.write().unwrap();
            *lock = value;
        }

        #[allow(dead_code)]
        pub fn swap(&self, value: u64, _: Ordering) -> u64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = value;
            prev
        }

        #[allow(dead_code)]
        pub fn compare_and_swap(
            &self,
            current: u64,
            new: u64,
            _: Ordering,
        ) -> u64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            if prev == current {
                *lock = new;
            };
            prev
        }

        #[allow(dead_code)]
        pub fn compare_exchange(
            &self,
            current: u64,
            new: u64,
            _: Ordering,
            _: Ordering,
        ) -> Result<u64, u64> {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            if prev == current {
                *lock = new;
                Ok(current)
            } else {
                Err(prev)
            }
        }

        #[allow(dead_code)]
        pub fn compare_exchange_weak(
            &self,
            current: u64,
            new: u64,
            success: Ordering,
            failure: Ordering,
        ) -> Result<u64, u64> {
            self.compare_exchange(current, new, success, failure)
        }

        #[allow(dead_code)]
        pub fn fetch_add(&self, val: u64, _: Ordering) -> u64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = prev.wrapping_add(val);
            prev
        }

        #[allow(dead_code)]
        pub fn fetch_sub(&self, val: u64, _: Ordering) -> u64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = prev.wrapping_sub(val);
            prev
        }

        #[allow(dead_code)]
        pub fn fetch_and(&self, val: u64, _: Ordering) -> u64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = prev & val;
            prev
        }

        #[allow(dead_code)]
        pub fn fetch_nand(&self, val: u64, _: Ordering) -> u64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = !(prev & val);
            prev
        }

        #[allow(dead_code)]
        pub fn fetch_or(&self, val: u64, _: Ordering) -> u64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = prev | val;
            prev
        }

        #[allow(dead_code)]
        pub fn fetch_xor(&self, val: u64, _: Ordering) -> u64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = prev ^ val;
            prev
        }
    }

    impl From<u64> for AtomicU64 {
        fn from(value: u64) -> Self {
            AtomicU64::new(value)
        }
    }

    #[derive(Debug, Default)]
    pub struct AtomicI64 {
        value: ShardedLock<i64>,
    }

    impl AtomicI64 {
        pub fn new(v: i64) -> Self {
            Self { value: ShardedLock::new(v) }
        }

        #[allow(dead_code)]
        pub fn get_mut(&mut self) -> &mut i64 {
            self.value.get_mut().unwrap()
        }

        #[allow(dead_code)]
        pub fn into_inner(self) -> i64 {
            self.value.into_inner().unwrap()
        }

        #[allow(dead_code)]
        pub fn load(&self, _: Ordering) -> i64 {
            *self.value.read().unwrap()
        }

        #[allow(dead_code)]
        pub fn store(&self, value: i64, _: Ordering) {
            let mut lock = self.value.write().unwrap();
            *lock = value;
        }

        #[allow(dead_code)]
        pub fn swap(&self, value: i64, _: Ordering) -> i64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = value;
            prev
        }

        #[allow(dead_code)]
        pub fn compare_and_swap(
            &self,
            current: i64,
            new: i64,
            _: Ordering,
        ) -> i64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            if prev == current {
                *lock = new;
            };
            prev
        }

        #[allow(dead_code)]
        pub fn compare_exchange(
            &self,
            current: i64,
            new: i64,
            _: Ordering,
            _: Ordering,
        ) -> Result<i64, i64> {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            if prev == current {
                *lock = new;
                Ok(current)
            } else {
                Err(prev)
            }
        }

        #[allow(dead_code)]
        pub fn compare_exchange_weak(
            &self,
            current: i64,
            new: i64,
            success: Ordering,
            failure: Ordering,
        ) -> Result<i64, i64> {
            self.compare_exchange(current, new, success, failure)
        }

        #[allow(dead_code)]
        pub fn fetch_add(&self, val: i64, _: Ordering) -> i64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = prev.wrapping_add(val);
            prev
        }

        #[allow(dead_code)]
        pub fn fetch_sub(&self, val: i64, _: Ordering) -> i64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = prev.wrapping_sub(val);
            prev
        }

        #[allow(dead_code)]
        pub fn fetch_and(&self, val: i64, _: Ordering) -> i64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = prev & val;
            prev
        }

        #[allow(dead_code)]
        pub fn fetch_nand(&self, val: i64, _: Ordering) -> i64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = !(prev & val);
            prev
        }

        #[allow(dead_code)]
        pub fn fetch_or(&self, val: i64, _: Ordering) -> i64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = prev | val;
            prev
        }

        #[allow(dead_code)]
        pub fn fetch_xor(&self, val: i64, _: Ordering) -> i64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = prev ^ val;
            prev
        }
    }

    impl From<i64> for AtomicI64 {
        fn from(value: i64) -> Self {
            AtomicI64::new(value)
        }
    }
}

#[cfg(any(
    target_arch = "mips",
    target_arch = "powerpc",
    feature = "mutex"
))]
pub use shim::{AtomicI64, AtomicU64};
<commit_msg>Make atomic_shim::AtomicU64::new a const fn<commit_after>///! Inline of `https://github.com/bltavares/atomic-shim`

#[cfg(not(any(
    target_arch = "mips",
    target_arch = "powerpc",
    feature = "mutex"
)))]
pub use std::sync::atomic::{AtomicI64, AtomicU64};
#[cfg(any(target_arch = "mips", target_arch = "powerpc", feature = "mutex"))]
mod shim {
    use crossbeam_utils::sync::ShardedLock;
    use std::sync::atomic::Ordering;

    #[derive(Debug, Default)]
    pub struct AtomicU64 {
        value: ShardedLock<u64>,
    }

    impl AtomicU64 {
        pub const fn new(v: u64) -> Self {
            Self { value: ShardedLock::new(v) }
        }

        #[allow(dead_code)]
        pub fn get_mut(&mut self) -> &mut u64 {
            self.value.get_mut().unwrap()
        }

        #[allow(dead_code)]
        pub fn into_inner(self) -> u64 {
            self.value.into_inner().unwrap()
        }

        #[allow(dead_code)]
        pub fn load(&self, _: Ordering) -> u64 {
            *self.value.read().unwrap()
        }

        #[allow(dead_code)]
        pub fn store(&self, value: u64, _: Ordering) {
            let mut lock = self.value.write().unwrap();
            *lock = value;
        }

        #[allow(dead_code)]
        pub fn swap(&self, value: u64, _: Ordering) -> u64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = value;
            prev
        }

        #[allow(dead_code)]
        pub fn compare_and_swap(
            &self,
            current: u64,
            new: u64,
            _: Ordering,
        ) -> u64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            if prev == current {
                *lock = new;
            };
            prev
        }

        #[allow(dead_code)]
        pub fn compare_exchange(
            &self,
            current: u64,
            new: u64,
            _: Ordering,
            _: Ordering,
        ) -> Result<u64, u64> {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            if prev == current {
                *lock = new;
                Ok(current)
            } else {
                Err(prev)
            }
        }

        #[allow(dead_code)]
        pub fn compare_exchange_weak(
            &self,
            current: u64,
            new: u64,
            success: Ordering,
            failure: Ordering,
        ) -> Result<u64, u64> {
            self.compare_exchange(current, new, success, failure)
        }

        #[allow(dead_code)]
        pub fn fetch_add(&self, val: u64, _: Ordering) -> u64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = prev.wrapping_add(val);
            prev
        }

        #[allow(dead_code)]
        pub fn fetch_sub(&self, val: u64, _: Ordering) -> u64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = prev.wrapping_sub(val);
            prev
        }

        #[allow(dead_code)]
        pub fn fetch_and(&self, val: u64, _: Ordering) -> u64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = prev & val;
            prev
        }

        #[allow(dead_code)]
        pub fn fetch_nand(&self, val: u64, _: Ordering) -> u64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = !(prev & val);
            prev
        }

        #[allow(dead_code)]
        pub fn fetch_or(&self, val: u64, _: Ordering) -> u64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = prev | val;
            prev
        }

        #[allow(dead_code)]
        pub fn fetch_xor(&self, val: u64, _: Ordering) -> u64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = prev ^ val;
            prev
        }
    }

    impl From<u64> for AtomicU64 {
        fn from(value: u64) -> Self {
            AtomicU64::new(value)
        }
    }

    #[derive(Debug, Default)]
    pub struct AtomicI64 {
        value: ShardedLock<i64>,
    }

    impl AtomicI64 {
        pub fn new(v: i64) -> Self {
            Self { value: ShardedLock::new(v) }
        }

        #[allow(dead_code)]
        pub fn get_mut(&mut self) -> &mut i64 {
            self.value.get_mut().unwrap()
        }

        #[allow(dead_code)]
        pub fn into_inner(self) -> i64 {
            self.value.into_inner().unwrap()
        }

        #[allow(dead_code)]
        pub fn load(&self, _: Ordering) -> i64 {
            *self.value.read().unwrap()
        }

        #[allow(dead_code)]
        pub fn store(&self, value: i64, _: Ordering) {
            let mut lock = self.value.write().unwrap();
            *lock = value;
        }

        #[allow(dead_code)]
        pub fn swap(&self, value: i64, _: Ordering) -> i64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = value;
            prev
        }

        #[allow(dead_code)]
        pub fn compare_and_swap(
            &self,
            current: i64,
            new: i64,
            _: Ordering,
        ) -> i64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            if prev == current {
                *lock = new;
            };
            prev
        }

        #[allow(dead_code)]
        pub fn compare_exchange(
            &self,
            current: i64,
            new: i64,
            _: Ordering,
            _: Ordering,
        ) -> Result<i64, i64> {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            if prev == current {
                *lock = new;
                Ok(current)
            } else {
                Err(prev)
            }
        }

        #[allow(dead_code)]
        pub fn compare_exchange_weak(
            &self,
            current: i64,
            new: i64,
            success: Ordering,
            failure: Ordering,
        ) -> Result<i64, i64> {
            self.compare_exchange(current, new, success, failure)
        }

        #[allow(dead_code)]
        pub fn fetch_add(&self, val: i64, _: Ordering) -> i64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = prev.wrapping_add(val);
            prev
        }

        #[allow(dead_code)]
        pub fn fetch_sub(&self, val: i64, _: Ordering) -> i64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = prev.wrapping_sub(val);
            prev
        }

        #[allow(dead_code)]
        pub fn fetch_and(&self, val: i64, _: Ordering) -> i64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = prev & val;
            prev
        }

        #[allow(dead_code)]
        pub fn fetch_nand(&self, val: i64, _: Ordering) -> i64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = !(prev & val);
            prev
        }

        #[allow(dead_code)]
        pub fn fetch_or(&self, val: i64, _: Ordering) -> i64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = prev | val;
            prev
        }

        #[allow(dead_code)]
        pub fn fetch_xor(&self, val: i64, _: Ordering) -> i64 {
            let mut lock = self.value.write().unwrap();
            let prev = *lock;
            *lock = prev ^ val;
            prev
        }
    }

    impl From<i64> for AtomicI64 {
        fn from(value: i64) -> Self {
            AtomicI64::new(value)
        }
    }
}

#[cfg(any(
    target_arch = "mips",
    target_arch = "powerpc",
    feature = "mutex"
))]
pub use shim::{AtomicI64, AtomicU64};
<|endoftext|>


<commit_before>use config::Config;
use error::BackendError;

pub mod anilist;

pub trait SyncBackend
where
    Self: Sized,
{
    fn init(config: &mut Config) -> Result<Self, BackendError>;
    fn find_series_by_name(&self, name: &str) -> Result<Vec<AnimeInfo>, BackendError>;
}

#[derive(Debug, Deserialize)]
pub struct AnimeInfo {
    pub id: u32,
    pub title: String,
    pub episodes: u32,
}
<commit_msg>Add remaining methods and structs to allow for a generic backend<commit_after>use chrono::{NaiveDate, Utc};
use config::Config;
use error::BackendError;

pub mod anilist;

pub trait SyncBackend
where
    Self: Sized,
{
    fn init(config: &mut Config) -> Result<Self, BackendError>;

    fn search_by_name(&self, name: &str) -> Result<Vec<AnimeInfo>, BackendError>;
    fn get_series_info_by_id(&self, id: u32) -> Result<AnimeInfo, BackendError>;

    fn get_list_entry(&self, info: AnimeInfo) -> Result<Option<AnimeEntry>, BackendError>;
    fn update_list_entry(&self, entry: &AnimeEntry) -> Result<(), BackendError>;
}

#[derive(Clone, Debug)]
pub struct AnimeInfo {
    pub id: u32,
    pub title: String,
    pub episodes: u32,
}

#[derive(Debug)]
pub struct AnimeEntry {
    pub info: AnimeInfo,
    pub watched_episodes: u32,
    pub score: f32,
    pub status: Status,
    pub start_date: Option<NaiveDate>,
    pub finish_date: Option<NaiveDate>,
}

impl AnimeEntry {
    pub fn new(info: AnimeInfo) -> AnimeEntry {
        AnimeEntry {
            info,
            watched_episodes: 0,
            score: 0.0,
            status: Status::PlanToWatch,
            start_date: Some(Utc::now().naive_utc().date()),
            finish_date: None,
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Status {
    Watching,
    Completed,
    OnHold,
    Dropped,
    PlanToWatch,
    Rewatching,
}
<|endoftext|>


<commit_before>use color::Color;

pub struct Program {
    image: Vec<Vec<Color>>,
}

impl Program {
    pub fn get(&self, coords: (usize, usize)) -> Option<Color> {
        unimplemented!();
    }

    pub fn neighbors(&self, coords: (usize, usize)) -> &[Color] {
        unimplemented!();
    }

    pub fn neighbors_with_coords(&self, coords: (usize, usize)) -> &[(usize, usize, Color)] {
        unimplemented!();
    }
}
<commit_msg>Implement `Program::get`<commit_after>use color::Color;

pub struct Program {
    size: (usize, usize),
    image: Vec<Color>,
}

impl Program {
    pub fn get(&self, coords: (usize, usize)) -> Option<Color> {
        coords_to_index(coords, &self.size).map(|index| self.image[index])
    }

    pub fn neighbors(&self, coords: (usize, usize)) -> &[Color] {
        unimplemented!();
    }

    pub fn neighbors_with_coords(&self, coords: (usize, usize)) -> &[(usize, usize, Color)] {
        unimplemented!();
    }
}

fn coords_to_index(coords: (usize, usize), size: &(usize, usize)) -> Option<usize> {
    let (x, y) = coords;
    let (width, height) = *size;

    if x >= width || y >= height {
        return None;
    }

    Some(width * y + x % width)
}

fn index_to_coords(index: usize, size: &(usize, usize)) -> Option<(usize, usize)> {
    let (width, height) = *size;

    if index >= width * height {
        return None;
    }

    let x = index % width;
    let y = index / width;

    Some((x, y))
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::{coords_to_index, index_to_coords};

    #[test]
    fn test_coords_to_index() {
        let size = (5, 5);
        assert_eq!(coords_to_index((0, 0), &size), Some(0));
        assert_eq!(coords_to_index((2, 0), &size), Some(2));
        assert_eq!(coords_to_index((0, 2), &size), Some(10));
        assert_eq!(coords_to_index((2, 2), &size), Some(12));
        assert_eq!(coords_to_index((4, 4), &size), Some(24));
        assert_eq!(coords_to_index((5, 5), &size), None);
    }

    #[test]
    fn test_index_to_coords() {
        let size = (5, 5);
        assert_eq!(index_to_coords(0, &size), Some((0, 0)));
        assert_eq!(index_to_coords(2, &size), Some((2, 0)));
        assert_eq!(index_to_coords(10, &size), Some((0, 2)));
        assert_eq!(index_to_coords(12, &size), Some((2, 2)));
        assert_eq!(index_to_coords(24, &size), Some((4, 4)));
        assert_eq!(index_to_coords(25, &size), None);
    }
}
<|endoftext|>


<commit_before>use super::common::*;
use crate::prelude::*;

use crate::idents;
use crate::model;
use crate::utils;

use crate::tyhandlers::ModelTypeSystem;

/// Expands the `com_class` attribute.
///
/// The attribute expansion results in the following items:
///
/// - Virtual table offset values for the different interfaces.
/// - `IUnknown` virtual table instance.
/// - `CoClass` trait implementation.
pub fn expand_com_class(
    attr_tokens: TokenStreamNightly,
    item_tokens: TokenStreamNightly,
) -> Result<TokenStreamNightly, model::ParseError>
{
    // Parse the attribute.
    let mut output = vec![];
    let cls = model::ComStruct::parse(&lib_name(), attr_tokens.into(), item_tokens.clone().into())?;
    let struct_ident = &cls.name;

    // IUnknown vtable match. As the primary query_interface is implemented
    // on the root IUnknown interface, the self_vtable here should already be
    // the IUnknown we need.
    let support_error_info_vtbl = quote!(
        <dyn intercom::ISupportErrorInfo as intercom::attributes::ComInterface<
            intercom::type_system::AutomationTypeSystem,
        >>::VTable
    );
    let mut query_interface_match_arms = vec![
        quote!(
            if riid == <dyn intercom::IUnknown as intercom::attributes::ComInterface<intercom::type_system::AutomationTypeSystem>>::iid() {
                ( &vtables._ISupportErrorInfo )
                    as *const &#support_error_info_vtbl
                    as *mut &#support_error_info_vtbl
                    as intercom::RawComPtr
            } else
        ),
        quote!(
            if riid == <dyn intercom::ISupportErrorInfo as intercom::attributes::ComInterface<intercom::type_system::AutomationTypeSystem>>::iid() {
                ( &vtables._ISupportErrorInfo )
                    as *const &#support_error_info_vtbl
                    as *mut &#support_error_info_vtbl
                    as intercom::RawComPtr
            } else
        ),
    ];
    let mut support_error_info_match_arms = vec![];

    // Gather the virtual table list struct field definitions and their values.
    // The definitions are needed when we define the virtual table list struct,
    // which is different for each com_class. The values are needed when we
    // construct the virtual table list.
    //
    // The primary IUnknown virtual table _MUST_ be at the beginning of the list.
    // This is done to ensure the IUnknown pointer matches the ComBoxData pointer.
    // We ensure this by defining the primary IUnknown methods on the
    // ISupportErrorInfo virtual table and having that at the beginning.
    let mut vtable_list_field_decls = vec![quote!(
        _ISupportErrorInfo:
            &'static <dyn intercom::ISupportErrorInfo as intercom::attributes::ComInterface<
                intercom::type_system::AutomationTypeSystem,
            >>::VTable
    )];
    let mut vtable_list_field_values = vec![quote!( _ISupportErrorInfo :
                <#struct_ident as intercom::attributes::ComImpl<
                    dyn intercom::ISupportErrorInfo, intercom::type_system::AutomationTypeSystem>>::vtable() )];

    // Create the vtable data for the additional interfaces.
    // The data should include the match-arms for the primary query_interface
    // and the vtable offsets used for the delegating query_interface impls.
    for itf in &cls.interfaces {
        for &ts in &[ModelTypeSystem::Automation, ModelTypeSystem::Raw] {
            // Various idents.
            let itf_variant = Ident::new(&format!("{}_{:?}", itf, ts), itf.span());
            let ts_type = ts.as_typesystem_type(itf.span());
            let maybe_dyn = match itf == struct_ident {
                true => quote!(),
                false => quote_spanned!(itf.span() => dyn),
            };

            // Store the field offset globally. We need this offset when implementing
            // the delegating query_interface methods. The only place where we know
            // the actual layout of the vtable is here. Thus we need to store this
            // offset somewhere where the com_impl's can access it.
            //
            // Rust doesn't allow pointer derefs or conversions in consts so we'll
            // use an inline fn instead. LLVM should be able to reduce this into a
            // constant expression during compilation.
            output.push(quote!(
                #[allow(non_snake_case)]
                impl intercom::attributes::ComClass<
                    #maybe_dyn #itf, #ts_type> for #struct_ident {

                    #[inline(always)]
                    fn offset() -> usize {
                        unsafe {
                            &intercom::ComBoxData::< #struct_ident >::null_vtable().#itf_variant
                                    as *const _ as usize
                        }
                    }
                }
            ));

            let itf_attrib_data = quote!(
                <#maybe_dyn #itf as intercom::attributes::ComInterface<#ts_type>>);
            let impl_attrib_data = quote!(
                <#struct_ident as intercom::attributes::ComImpl<#maybe_dyn #itf, #ts_type>>);

            // Add the interface in the vtable list.
            vtable_list_field_decls.push(quote!( #itf_variant : &'static #itf_attrib_data::VTable));
            vtable_list_field_values.push(quote!( #itf_variant : #impl_attrib_data::vtable()));

            // Define the query_interface match arm for the current interface.
            // This just gets the correct interface vtable reference from the list
            // of vtables.
            query_interface_match_arms.push(quote!(
                if riid == #itf_attrib_data::iid() {
                    &vtables.#itf_variant
                        as *const &#itf_attrib_data::VTable
                        as *mut &#itf_attrib_data::VTable
                        as intercom::RawComPtr
                } else
            ));

            // Define the support error info match arms.
            support_error_info_match_arms.push(quote!(
                if riid == <#maybe_dyn #itf as intercom::attributes::ComInterface<#ts_type>>::iid() {
                    true
                } else
            ));
        }
    }

    /////////////////////
    // ISupportErrorInfo virtual table instance.
    //
    // The primary IUnknown virtual table is embedded in this one.
    let iunknown_vtbl = quote!(
        <dyn intercom::IUnknown as intercom::attributes::ComInterface<
            intercom::type_system::AutomationTypeSystem,
        >>::VTable
    );
    output.push(quote!(
        #[allow(non_upper_case_globals)]
        impl intercom::attributes::ComImpl<
            intercom::ISupportErrorInfo, intercom::type_system::AutomationTypeSystem>
            for #struct_ident {

            fn vtable() -> &'static <dyn intercom::ISupportErrorInfo as intercom::attributes::ComInterface<intercom::type_system::AutomationTypeSystem>>::VTable
            {
                type T = <dyn intercom::ISupportErrorInfo as intercom::attributes::ComInterface<intercom::type_system::AutomationTypeSystem>>::VTable;
                & T {
                    __base : {
                        type Vtbl = #iunknown_vtbl;
                        Vtbl {
                            query_interface
                                : intercom::ComBoxData::< #struct_ident >
                                    ::query_interface_ptr,
                            add_ref
                                : intercom::ComBoxData::< #struct_ident >
                                    ::add_ref_ptr,
                            release
                                : intercom::ComBoxData::< #struct_ident >
                                    ::release_ptr,
                        }
                    },
                    interface_supports_error_info
                        : intercom::ComBoxData::< #struct_ident >
                            ::interface_supports_error_info_ptr,
                }
            }
        }
    ));

    // Mark the struct as having IUnknown.
    output.push(quote!(
        impl intercom::HasInterface< intercom::IUnknown > for #struct_ident {}
    ));

    // The CoClass implementation.
    //
    // Define the vtable list struct first. This lists the vtables of all the
    // interfaces that the coclass implements.

    // VTableList struct definition.
    let vtable_list_ident = Ident::new(
        &format!("__intercom_vtable_for_{}", struct_ident),
        Span::call_site(),
    );
    let visibility = &cls.visibility;
    output.push(quote!(
        #[allow(non_snake_case)]
        #[doc(hidden)]
        #visibility struct #vtable_list_ident {
            #( #vtable_list_field_decls ),*
        }
    ));

    // The actual CoClass implementation.
    output.push(quote!(
        impl intercom::CoClass for #struct_ident {
            type VTableList = #vtable_list_ident;
            fn create_vtable_list() -> Self::VTableList {
                #vtable_list_ident {
                    #( #vtable_list_field_values ),*
                }
            }
            fn query_interface(
                vtables : &Self::VTableList,
                riid : intercom::REFIID,
            ) -> intercom::RawComResult< intercom::RawComPtr > {
                if riid.is_null() { return Err( intercom::raw::E_NOINTERFACE ); }
                unsafe {
                    let riid = &*riid;
                    Ok(
                        #( #query_interface_match_arms )*
                        { return Err( intercom::raw::E_NOINTERFACE ) }
                    )
                }
            }

            fn interface_supports_error_info(
                riid : intercom::REFIID
            ) -> bool
            {
                if riid.is_null() { return false; }
                unsafe {
                    let riid = &*riid;
                    #( #support_error_info_match_arms )*
                    { false }
                }
            }
        }
    ));

    // CLSID constant for the class.
    let clsid_ident = idents::clsid(struct_ident);
    if let Some(ref guid) = cls.clsid {
        let clsid_guid_tokens = utils::get_guid_tokens(guid, Span::call_site());
        let clsid_doc = format!("`{}` class ID.", struct_ident);
        let clsid_const = quote!(
            #[allow(non_upper_case_globals)]
            #[doc = #clsid_doc ]
            pub const #clsid_ident : intercom::CLSID = #clsid_guid_tokens;
        );
        output.push(clsid_const);
    }

    output.push(
        create_get_typeinfo_function(&cls)
            .map_err(|e| model::ParseError::ComStruct(cls.name.to_string(), e))?,
    );

    Ok(tokens_to_tokenstream(item_tokens, output))
}

fn create_get_typeinfo_function(cls: &model::ComStruct) -> Result<TokenStream, String>
{
    let fn_name = Ident::new(
        &format!("get_intercom_coclass_info_for_{}", cls.name),
        Span::call_site(),
    );
    let cls_ident = &cls.name;
    let cls_name = cls.name.to_string();
    let clsid = match &cls.clsid {
        Some(guid) => guid,
        None => {
            return Ok(quote!(
                pub(crate) fn #fn_name() -> Vec<intercom::typelib::TypeInfo>
                { vec![] }
            ))
        }
    };
    let clsid_tokens = utils::get_guid_tokens(&clsid, Span::call_site());
    let (interfaces, interface_info): (Vec<_>, Vec<_>) = cls
        .interfaces
        .iter()
        .map(|itf_ident| {
            let itf_name = itf_ident.to_string();
            let maybe_dyn = match itf_ident == &cls.name {
                true => quote!(),
                false => quote_spanned!(itf_ident.span() => dyn),
            };
            (
                quote!( intercom::typelib::InterfaceRef {
                    name: #itf_name.into(),
                    iid_automation: <#maybe_dyn #itf_ident as intercom::attributes::ComInterface<intercom::type_system::AutomationTypeSystem>>::iid().clone(),
                    iid_raw: <#maybe_dyn #itf_ident as intercom::attributes::ComInterface<intercom::type_system::RawTypeSystem>>::iid().clone(),
                } ),
                quote!(
                    r.extend(<#maybe_dyn #itf_ident as intercom::attributes::InterfaceHasTypeInfo>::gather_type_info());
                ),
            )
        })
        .unzip();
    Ok(quote!(
        impl intercom::attributes::HasTypeInfo for #cls_ident
        {
            fn gather_type_info() -> Vec<intercom::typelib::TypeInfo>
            {
                let mut r = vec![ intercom::typelib::TypeInfo::Class(
                    intercom::ComBox::new( intercom::typelib::CoClass::__new(
                        #cls_name.into(),
                        #clsid_tokens,
                        vec![ #( #interfaces ),* ]
                    ) ) )
                ];
                #( #interface_info )*
                r
            }
        }
    ))
}
<commit_msg>Suppress clippy warnings in generated code<commit_after>use super::common::*;
use crate::prelude::*;

use crate::idents;
use crate::model;
use crate::utils;

use crate::tyhandlers::ModelTypeSystem;

/// Expands the `com_class` attribute.
///
/// The attribute expansion results in the following items:
///
/// - Virtual table offset values for the different interfaces.
/// - `IUnknown` virtual table instance.
/// - `CoClass` trait implementation.
pub fn expand_com_class(
    attr_tokens: TokenStreamNightly,
    item_tokens: TokenStreamNightly,
) -> Result<TokenStreamNightly, model::ParseError>
{
    // Parse the attribute.
    let mut output = vec![];
    let cls = model::ComStruct::parse(&lib_name(), attr_tokens.into(), item_tokens.clone().into())?;
    let struct_ident = &cls.name;

    // IUnknown vtable match. As the primary query_interface is implemented
    // on the root IUnknown interface, the self_vtable here should already be
    // the IUnknown we need.
    let support_error_info_vtbl = quote!(
        <dyn intercom::ISupportErrorInfo as intercom::attributes::ComInterface<
            intercom::type_system::AutomationTypeSystem,
        >>::VTable
    );
    let mut query_interface_match_arms = vec![
        quote!(
            if riid == <dyn intercom::IUnknown as intercom::attributes::ComInterface<intercom::type_system::AutomationTypeSystem>>::iid() {
                ( &vtables._ISupportErrorInfo )
                    as *const &#support_error_info_vtbl
                    as *mut &#support_error_info_vtbl
                    as intercom::RawComPtr
            } else
        ),
        quote!(
            if riid == <dyn intercom::ISupportErrorInfo as intercom::attributes::ComInterface<intercom::type_system::AutomationTypeSystem>>::iid() {
                ( &vtables._ISupportErrorInfo )
                    as *const &#support_error_info_vtbl
                    as *mut &#support_error_info_vtbl
                    as intercom::RawComPtr
            } else
        ),
    ];
    let mut support_error_info_match_arms = vec![];

    // Gather the virtual table list struct field definitions and their values.
    // The definitions are needed when we define the virtual table list struct,
    // which is different for each com_class. The values are needed when we
    // construct the virtual table list.
    //
    // The primary IUnknown virtual table _MUST_ be at the beginning of the list.
    // This is done to ensure the IUnknown pointer matches the ComBoxData pointer.
    // We ensure this by defining the primary IUnknown methods on the
    // ISupportErrorInfo virtual table and having that at the beginning.
    let mut vtable_list_field_decls = vec![quote!(
        _ISupportErrorInfo:
            &'static <dyn intercom::ISupportErrorInfo as intercom::attributes::ComInterface<
                intercom::type_system::AutomationTypeSystem,
            >>::VTable
    )];
    let mut vtable_list_field_values = vec![quote!( _ISupportErrorInfo :
                <#struct_ident as intercom::attributes::ComImpl<
                    dyn intercom::ISupportErrorInfo, intercom::type_system::AutomationTypeSystem>>::vtable() )];

    // Create the vtable data for the additional interfaces.
    // The data should include the match-arms for the primary query_interface
    // and the vtable offsets used for the delegating query_interface impls.
    for itf in &cls.interfaces {
        for &ts in &[ModelTypeSystem::Automation, ModelTypeSystem::Raw] {
            // Various idents.
            let itf_variant = Ident::new(&format!("{}_{:?}", itf, ts), itf.span());
            let ts_type = ts.as_typesystem_type(itf.span());
            let maybe_dyn = match itf == struct_ident {
                true => quote!(),
                false => quote_spanned!(itf.span() => dyn),
            };

            // Store the field offset globally. We need this offset when implementing
            // the delegating query_interface methods. The only place where we know
            // the actual layout of the vtable is here. Thus we need to store this
            // offset somewhere where the com_impl's can access it.
            //
            // Rust doesn't allow pointer derefs or conversions in consts so we'll
            // use an inline fn instead. LLVM should be able to reduce this into a
            // constant expression during compilation.
            output.push(quote!(
                #[allow(non_snake_case)]
                impl intercom::attributes::ComClass<
                    #maybe_dyn #itf, #ts_type> for #struct_ident {

                    #[inline(always)]
                    fn offset() -> usize {
                        unsafe {
                            &intercom::ComBoxData::< #struct_ident >::null_vtable().#itf_variant
                                    as *const _ as usize
                        }
                    }
                }
            ));

            let itf_attrib_data = quote!(
                <#maybe_dyn #itf as intercom::attributes::ComInterface<#ts_type>>);
            let impl_attrib_data = quote!(
                <#struct_ident as intercom::attributes::ComImpl<#maybe_dyn #itf, #ts_type>>);

            // Add the interface in the vtable list.
            vtable_list_field_decls.push(quote!( #itf_variant : &'static #itf_attrib_data::VTable));
            vtable_list_field_values.push(quote!( #itf_variant : #impl_attrib_data::vtable()));

            // Define the query_interface match arm for the current interface.
            // This just gets the correct interface vtable reference from the list
            // of vtables.
            query_interface_match_arms.push(quote!(
                if riid == #itf_attrib_data::iid() {
                    &vtables.#itf_variant
                        as *const &#itf_attrib_data::VTable
                        as *mut &#itf_attrib_data::VTable
                        as intercom::RawComPtr
                } else
            ));

            // Define the support error info match arms.
            support_error_info_match_arms.push(quote!(
                if riid == <#maybe_dyn #itf as intercom::attributes::ComInterface<#ts_type>>::iid() {
                    true
                } else
            ));
        }
    }

    /////////////////////
    // ISupportErrorInfo virtual table instance.
    //
    // The primary IUnknown virtual table is embedded in this one.
    let iunknown_vtbl = quote!(
        <dyn intercom::IUnknown as intercom::attributes::ComInterface<
            intercom::type_system::AutomationTypeSystem,
        >>::VTable
    );
    output.push(quote!(
        #[allow(non_upper_case_globals)]
        impl intercom::attributes::ComImpl<
            intercom::ISupportErrorInfo, intercom::type_system::AutomationTypeSystem>
            for #struct_ident {

            fn vtable() -> &'static <dyn intercom::ISupportErrorInfo as intercom::attributes::ComInterface<intercom::type_system::AutomationTypeSystem>>::VTable
            {
                type T = <dyn intercom::ISupportErrorInfo as intercom::attributes::ComInterface<intercom::type_system::AutomationTypeSystem>>::VTable;
                & T {
                    __base : {
                        type Vtbl = #iunknown_vtbl;
                        Vtbl {
                            query_interface
                                : intercom::ComBoxData::< #struct_ident >
                                    ::query_interface_ptr,
                            add_ref
                                : intercom::ComBoxData::< #struct_ident >
                                    ::add_ref_ptr,
                            release
                                : intercom::ComBoxData::< #struct_ident >
                                    ::release_ptr,
                        }
                    },
                    interface_supports_error_info
                        : intercom::ComBoxData::< #struct_ident >
                            ::interface_supports_error_info_ptr,
                }
            }
        }
    ));

    // Mark the struct as having IUnknown.
    output.push(quote!(
        impl intercom::HasInterface< intercom::IUnknown > for #struct_ident {}
    ));

    // The CoClass implementation.
    //
    // Define the vtable list struct first. This lists the vtables of all the
    // interfaces that the coclass implements.

    // VTableList struct definition.
    let vtable_list_ident = Ident::new(
        &format!("__intercom_vtable_for_{}", struct_ident),
        Span::call_site(),
    );
    let visibility = &cls.visibility;
    output.push(quote!(
        #[allow(non_snake_case)]
        #[doc(hidden)]
        #visibility struct #vtable_list_ident {
            #( #vtable_list_field_decls ),*
        }
    ));

    // The actual CoClass implementation.
    output.push(quote!(
        #[allow(clippy::all)]
        impl intercom::CoClass for #struct_ident {
            type VTableList = #vtable_list_ident;
            fn create_vtable_list() -> Self::VTableList {
                #vtable_list_ident {
                    #( #vtable_list_field_values ),*
                }
            }
            fn query_interface(
                vtables : &Self::VTableList,
                riid : intercom::REFIID,
            ) -> intercom::RawComResult< intercom::RawComPtr > {
                if riid.is_null() { return Err( intercom::raw::E_NOINTERFACE ); }
                unsafe {
                    let riid = &*riid;
                    Ok(
                        #( #query_interface_match_arms )*
                        { return Err( intercom::raw::E_NOINTERFACE ) }
                    )
                }
            }

            fn interface_supports_error_info(
                riid : intercom::REFIID
            ) -> bool
            {
                if riid.is_null() { return false; }
                unsafe {
                    let riid = &*riid;
                    #( #support_error_info_match_arms )*
                    { false }
                }
            }
        }
    ));

    // CLSID constant for the class.
    let clsid_ident = idents::clsid(struct_ident);
    if let Some(ref guid) = cls.clsid {
        let clsid_guid_tokens = utils::get_guid_tokens(guid, Span::call_site());
        let clsid_doc = format!("`{}` class ID.", struct_ident);
        let clsid_const = quote!(
            #[allow(non_upper_case_globals)]
            #[doc = #clsid_doc ]
            pub const #clsid_ident : intercom::CLSID = #clsid_guid_tokens;
        );
        output.push(clsid_const);
    }

    output.push(
        create_get_typeinfo_function(&cls)
            .map_err(|e| model::ParseError::ComStruct(cls.name.to_string(), e))?,
    );

    Ok(tokens_to_tokenstream(item_tokens, output))
}

fn create_get_typeinfo_function(cls: &model::ComStruct) -> Result<TokenStream, String>
{
    let fn_name = Ident::new(
        &format!("get_intercom_coclass_info_for_{}", cls.name),
        Span::call_site(),
    );
    let cls_ident = &cls.name;
    let cls_name = cls.name.to_string();
    let clsid = match &cls.clsid {
        Some(guid) => guid,
        None => {
            return Ok(quote!(
                pub(crate) fn #fn_name() -> Vec<intercom::typelib::TypeInfo>
                { vec![] }
            ))
        }
    };
    let clsid_tokens = utils::get_guid_tokens(&clsid, Span::call_site());
    let (interfaces, interface_info): (Vec<_>, Vec<_>) = cls
        .interfaces
        .iter()
        .map(|itf_ident| {
            let itf_name = itf_ident.to_string();
            let maybe_dyn = match itf_ident == &cls.name {
                true => quote!(),
                false => quote_spanned!(itf_ident.span() => dyn),
            };
            (
                quote!( intercom::typelib::InterfaceRef {
                    name: #itf_name.into(),
                    iid_automation: <#maybe_dyn #itf_ident as intercom::attributes::ComInterface<intercom::type_system::AutomationTypeSystem>>::iid().clone(),
                    iid_raw: <#maybe_dyn #itf_ident as intercom::attributes::ComInterface<intercom::type_system::RawTypeSystem>>::iid().clone(),
                } ),
                quote!(
                    r.extend(<#maybe_dyn #itf_ident as intercom::attributes::InterfaceHasTypeInfo>::gather_type_info());
                ),
            )
        })
        .unzip();
    Ok(quote!(
        impl intercom::attributes::HasTypeInfo for #cls_ident
        {
            fn gather_type_info() -> Vec<intercom::typelib::TypeInfo>
            {
                let mut r = vec![ intercom::typelib::TypeInfo::Class(
                    intercom::ComBox::new( intercom::typelib::CoClass::__new(
                        #cls_name.into(),
                        #clsid_tokens,
                        vec![ #( #interfaces ),* ]
                    ) ) )
                ];
                #( #interface_info )*
                r
            }
        }
    ))
}
<|endoftext|>


<commit_before>
//! manage endpoint `/changes/`

use clap;
use gerritlib::error::GGRError;
use gerritlib::error::GGRResult;
use gerritlib::gerrit::Gerrit;
use config;

/// proxy function of implemented features
///
/// Currently implemented sub commands:
///
/// * query
pub fn manage(x: &clap::ArgMatches) -> GGRResult<()> {
    match x.subcommand() {
        ("query", Some(y)) => { query(y) },
        _ => {
            println!("{}", x.usage());
            Ok(())
        },
    }
}

/// creat, call and prints queries to a gerrit server
fn query(y: &clap::ArgMatches) -> GGRResult<()> {
    let userquery = Query::from(y.values_of("userquery").unwrap());

    let configfile = try!(config::ConfigFile::discover(".", ".ggr.conf"));
    let config = config::Config::from_configfile(configfile);

    if ! config.is_valid() {
        return Err(GGRError::General("problem with configfile".to_string()));
    }

    let gerrit = Gerrit::new(config.get_base_url());

    let response_changes = gerrit.changes(Some(userquery.get_query()), None);

    match response_changes {
        Ok(changeinfos) => {
            for ci in changeinfos {
                println!("{}", ci);
            }
        },
        Err(x) => {
            return Err(x);
        }
    }

    Ok(())
}

#[derive(Clone)]
struct Query<'query> {
    query: Vec<&'query str>,
}

impl<'value> From<clap::Values<'value>> for Query<'value> {
    fn from(v: clap::Values<'value>) -> Query<'value> {
        let mut qb = Query::new();

        for (_, arg) in v.enumerate() {
            qb.add_str(arg);
        }
        qb
    }
}

impl<'query> Query<'query> {
    pub fn new() -> Query<'query> {
        Query {
            query: Vec::new()
        }
    }

    /// Split at first ':' from left so we can have ':' in search string
    pub fn add_str(&mut self, x: &'query str) -> &mut Query<'query> {
        // TODO: add preparsing of `x` to prevent missuse like `x=y` instead of `x:y`.
        self.query.push(x);
        self
    }

    pub fn get_query(&self) -> &Vec<&'query str> {
        &self.query
    }
}
<commit_msg>changes: proper error handling (remove unwrap)<commit_after>
//! manage endpoint `/changes/`

use clap;
use gerritlib::error::GGRError;
use gerritlib::error::GGRResult;
use gerritlib::gerrit::Gerrit;
use config;

/// proxy function of implemented features
///
/// Currently implemented sub commands:
///
/// * query
pub fn manage(x: &clap::ArgMatches) -> GGRResult<()> {
    match x.subcommand() {
        ("query", Some(y)) => { query(y) },
        _ => {
            println!("{}", x.usage());
            Ok(())
        },
    }
}

/// creat, call and prints queries to a gerrit server
fn query(y: &clap::ArgMatches) -> GGRResult<()> {
    let mut userquery = match y.values_of("userquery") {
        Some(x) => Query::from(x),
        None => return Err(GGRError::General("No or bad userquery".into())),
    };

    let configfile = try!(config::ConfigFile::discover(".", ".ggr.conf"));
    let config = config::Config::from_configfile(configfile);

    if ! config.is_valid() {
        return Err(GGRError::General("problem with configfile".to_string()));
    }

    let gerrit = Gerrit::new(config.get_base_url());

    let response_changes = gerrit.changes(Some(userquery.get_query()), None);

    match response_changes {
        Ok(changeinfos) => {
            for ci in changeinfos {
                println!("{}", ci);
            }
        },
        Err(x) => {
            return Err(x);
        }
    }

    Ok(())
}

#[derive(Clone)]
struct Query<'query> {
    query: Vec<&'query str>,
}

impl<'value> From<clap::Values<'value>> for Query<'value> {
    fn from(v: clap::Values<'value>) -> Query<'value> {
        let mut qb = Query::new();

        for (_, arg) in v.enumerate() {
            qb.add_str(arg);
        }
        qb
    }
}

impl<'query> Query<'query> {
    pub fn new() -> Query<'query> {
        Query {
            query: Vec::new()
        }
    }

    /// Split at first ':' from left so we can have ':' in search string
    pub fn add_str(&mut self, x: &'query str) -> &mut Query<'query> {
        // TODO: add preparsing of `x` to prevent missuse like `x=y` instead of `x:y`.
        self.query.push(x);
        self
    }

    pub fn get_query(&self) -> &Vec<&'query str> {
        &self.query
    }
}
<|endoftext|>


<commit_before>// #[ allow( unused_imports ) ]
// use test_tools::test_suite;

//

#[ derive( Debug ) ]
struct SmokeModuleTest< 'a >
{
  pub dependency_name : &'a str,
  pub version : &'a str,
  pub local_path : &'a str,
  pub code : String,
  pub test_path : std::path::PathBuf,
  pub test_postfix : &'a str,
}

impl< 'a > SmokeModuleTest< 'a >
{
  fn new( dependency_name : &'a str ) -> SmokeModuleTest< 'a >
  {
    let mut test_path = std::env::temp_dir();
    test_path.push( dependency_name );

    SmokeModuleTest
    {
      dependency_name,
      version : "*",
      local_path : "",
      code : "".to_string(),
      test_path,
      test_postfix : "_smoke_test",
    }
  }

  fn version( &mut self, version : &'a str ) -> &mut SmokeModuleTest< 'a >
  {
    self.version = version;
    self
  }

  fn local_path( &mut self, local_path : &'a str ) -> &mut SmokeModuleTest< 'a >
  {
    self.local_path = local_path;
    self
  }

  fn test_postfix( &mut self, src : &'a str )
  {
    self.test_postfix = src;
  }

  fn code( &mut self, code : String ) -> &mut SmokeModuleTest< 'a >
  {
    self.code = code;
    self
  }

  fn form( &mut self ) -> Result< (), &'static str >
  {
    std::fs::create_dir( &self.test_path ).unwrap();

    let mut test_path = self.test_path.clone();

    /* create binary test module */
    let test_name = format!( "{}{}", self.dependency_name, self.test_postfix );
    let output = std::process::Command::new( "cargo" )
    .current_dir( &test_path )
    .args([ "new", "--bin", &test_name ])
    .output()
    .expect( "Failed to execute command" );
    println!( "{}", std::str::from_utf8( &output.stderr ).expect( "Found invalid UTF-8" ) );

    test_path.push( test_name );

    /* setup config */
    let local_path = if self.local_path == "" { "".to_string() } else { format!( ", path = \"{}\"", self.local_path ) };
    let dependencies_section = format!( "{} = {{ version = \"{}\"{} }}", self.dependency_name, self.version, &local_path );
    let config_data = format!
    (
      "[package]\n\
      edition = \"2018\"\n\
      name = \"{}_smoke_test\"\n\
      version = \"0.0.1\"\n\
      \n\
      [dependencies]\n\
      {}",
      &self.dependency_name,
      &dependencies_section
    );
    let mut config_path = test_path.clone();
    config_path.push( "Cargo.toml" );
    dbg!( &config_data );
    std::fs::write( config_path, config_data ).unwrap();

    /* write code */
    test_path.push( "src" );
    test_path.push( "main.rs" );
    if self.code == ""
    {
      self.code = format!( "use ::{}::*;", self.dependency_name );
    }
    let code = format!
    (
      "#[ allow( unused_imports ) ]\n\
      fn main()\n\
      {{\n  \
        {}\n\
      }}",
      self.code
    );
    dbg!( &code );
    std::fs::write( &test_path, code ).unwrap();

    Ok( () )
  }

  fn perform( &self ) -> Result<(), &'static str>
  {
    let mut test_path = self.test_path.clone();
    let test_name = format!( "{}{}", self.dependency_name, self.test_postfix );
    test_path.push( test_name );

    let output = std::process::Command::new( "cargo" )
    .current_dir( test_path )
    .args([ "run", "--release" ])
    .output()
    .unwrap();
    println!( "status : {}", output.status );
    println!( "{}", std::str::from_utf8( &output.stdout ).expect( "Found invalid UTF-8" ) );
    println!( "{}", std::str::from_utf8( &output.stderr ).expect( "Found invalid UTF-8" ) );
    assert!( output.status.success(), "Smoke test failed" );

    Ok( () )
  }

  fn clean( &self, force : bool ) -> Result<(), &'static str>
  {
    let result = std::fs::remove_dir_all( &self.test_path );
    if force
    {
      result.unwrap_or_default();
    }
    else
    {
      let msg = format!( "Cannot remove temporary directory {}. Please, remove it manually", &self.test_path.display() );
      result.expect( &msg );
    }
    Ok( () )
  }

}

//
//   index!
//   {
//
//     new,
//     version,
//     local_path,
//     code,
//     form,
//     perform,
//     clean,
//
//   }
//
//

fn smoke_test_run( test_name : &'static str, local : bool )
{
  let module_name = std::env::var( "CARGO_PKG_NAME" ).unwrap();
  let module_path = std::env::var( "CARGO_MANIFEST_DIR" ).unwrap();

  let mut code_path = std::path::PathBuf::from( module_path.clone() );

  code_path.push( "rust" );
  code_path.push( "test" );
  code_path.push( if module_name.starts_with( "w" ) { &module_name[ 1.. ] } else { module_name.as_str() } );
  code_path.push( "_asset" );
  code_path.push( "smoke.rs" );

  let mut t = SmokeModuleTest::new( module_name.as_str() );
  t.clean( true ).unwrap();
  t.test_postfix( test_name );

  let data;
  if code_path.exists()
  {
    data = std::fs::read_to_string( code_path ).unwrap();
    t.code( data );
  }

  t.version( "*" );
  if local
  {
    t.local_path( module_path.as_str() );
  }

  t.form().unwrap();
  t.perform().unwrap();
  t.clean( false ).unwrap();

}

//

// qqq : make it working
// #[ test ]
// fn local_smoke_test()
// {
//   if let Ok( value ) = std::env::var( "WITH_SMOKE" )
//   {
//     match value.as_str()
//     {
//       "false" => {},
//       "local" => smoke_test_run( "local_smoke_test", true ),
//       "published" => {},
//       _ =>
//       {
//         smoke_test_run( "local_smoke_test", true );
//       },
//     }
//   }
// }

//

#[ test ]
fn published_smoke_test()
{
  if let Ok( value ) = std::env::var( "WITH_SMOKE" )
  {
    match value.as_str()
    {
      "false" | "0" => {},
      "local" => {},
      "published" => smoke_test_run( "published_smoke_test", false ),
      _ =>
      {
        smoke_test_run( "published_smoke_test", false );
      },
    }
  }
}
<commit_msg>Improve smoke test `smoke_test`, run local and published test in parallel<commit_after>// #[ allow( unused_imports ) ]
// use test_tools::test_suite;

//

#[ derive( Debug ) ]
struct SmokeModuleTest< 'a >
{
  pub dependency_name : &'a str,
  pub version : &'a str,
  pub local_path : &'a str,
  pub code : String,
  pub test_path : std::path::PathBuf,
  pub test_postfix : &'a str,
}

impl< 'a > SmokeModuleTest< 'a >
{
  fn new( dependency_name : &'a str ) -> SmokeModuleTest< 'a >
  {
    let test_postfix = "_smoke_test";
    let smoke_test_path = format!( "{}{}", dependency_name, test_postfix );
    let mut test_path = std::env::temp_dir();
    test_path.push( smoke_test_path );

    SmokeModuleTest
    {
      dependency_name,
      version : "*",
      local_path : "",
      code : "".to_string(),
      test_path,
      test_postfix,
    }
  }

  fn version( &mut self, version : &'a str ) -> &mut SmokeModuleTest< 'a >
  {
    self.version = version;
    self
  }

  fn local_path( &mut self, local_path : &'a str ) -> &mut SmokeModuleTest< 'a >
  {
    self.local_path = local_path;
    self
  }

  fn test_postfix( &mut self, test_postfix : &'a str ) -> &mut SmokeModuleTest< 'a >
  {
    self.test_postfix = test_postfix;
    let smoke_test_path = format!( "{}{}", self.dependency_name, test_postfix );
    self.test_path.pop();
    self.test_path.push( smoke_test_path );
    self
  }

  fn code( &mut self, code : String ) -> &mut SmokeModuleTest< 'a >
  {
    self.code = code;
    self
  }

  fn form( &mut self ) -> Result< (), &'static str >
  {
    std::fs::create_dir( &self.test_path ).unwrap();

    let mut test_path = self.test_path.clone();

    /* create binary test module */
    let test_name = format!( "{}{}", self.dependency_name, self.test_postfix );
    let output = std::process::Command::new( "cargo" )
    .current_dir( &test_path )
    .args([ "new", "--bin", &test_name ])
    .output()
    .expect( "Failed to execute command" );
    println!( "{}", std::str::from_utf8( &output.stderr ).expect( "Found invalid UTF-8" ) );

    test_path.push( test_name );

    /* setup config */
    let local_path = if self.local_path == "" { "".to_string() } else { format!( ", path = \"{}\"", self.local_path ) };
    let dependencies_section = format!( "{} = {{ version = \"{}\"{} }}", self.dependency_name, self.version, &local_path );
    let config_data = format!
    (
      "[package]
      edition = \"2018\"
      name = \"{}_smoke_test\"
      version = \"0.0.1\"

      [dependencies]
      {}",
      &self.dependency_name,
      &dependencies_section
    );
    let mut config_path = test_path.clone();
    config_path.push( "Cargo.toml" );
    dbg!( &config_data );
    std::fs::write( config_path, config_data ).unwrap();

    /* write code */
    test_path.push( "src" );
    test_path.push( "main.rs" );
    if self.code == ""
    {
      self.code = format!( "use ::{}::*;", self.dependency_name );
    }
    let code = format!
    (
      "#[ allow( unused_imports ) ]
      fn main()
      {{
        {}
      }}",
      self.code
    );
    dbg!( &code );
    std::fs::write( &test_path, code ).unwrap();

    Ok( () )
  }

  fn perform( &self ) -> Result<(), &'static str>
  {
    let mut test_path = self.test_path.clone();
    let test_name = format!( "{}{}", self.dependency_name, self.test_postfix );
    test_path.push( test_name );

    let output = std::process::Command::new( "cargo" )
    .current_dir( test_path )
    .args([ "run", "--release" ])
    .output()
    .unwrap();
    println!( "status : {}", output.status );
    println!( "{}", std::str::from_utf8( &output.stdout ).expect( "Found invalid UTF-8" ) );
    println!( "{}", std::str::from_utf8( &output.stderr ).expect( "Found invalid UTF-8" ) );
    assert!( output.status.success(), "Smoke test failed" );

    Ok( () )
  }

  fn clean( &self, force : bool ) -> Result<(), &'static str>
  {
    let result = std::fs::remove_dir_all( &self.test_path );
    if force
    {
      result.unwrap_or_default();
    }
    else
    {
      let msg = format!( "Cannot remove temporary directory {}. Please, remove it manually", &self.test_path.display() );
      result.expect( &msg );
    }
    Ok( () )
  }
}

//
//   index!
//   {
//
//     new,
//     version,
//     local_path,
//     code,
//     form,
//     perform,
//     clean,
//
//   }
//
//

fn smoke_test_run( test_name : &'static str, local : bool )
{
  let module_name = std::env::var( "CARGO_PKG_NAME" ).unwrap();
  let module_path = std::env::var( "CARGO_MANIFEST_DIR" ).unwrap();

  let mut code_path = std::path::PathBuf::from( module_path.clone() );
  code_path.push( "rust" );
  code_path.push( "test" );
  code_path.push( if module_name.starts_with( "w" ) { &module_name[ 1.. ] } else { module_name.as_str() } );
  code_path.push( "_asset" );
  code_path.push( "smoke.rs" );

  let mut t = SmokeModuleTest::new( module_name.as_str() );
  t.test_postfix( test_name );
  t.clean( true ).unwrap();

  let data;
  if code_path.exists()
  {
    data = std::fs::read_to_string( code_path ).unwrap();
    t.code( data );
  }

  t.version( "*" );
  if local
  {
    t.local_path( module_path.as_str() );
  }

  t.form().unwrap();
  t.perform().unwrap();
  t.clean( false ).unwrap();
}

//

// qqq : make it working
#[ test ]
fn local_smoke_test()
{
  if let Ok( value ) = std::env::var( "WITH_SMOKE" )
  {
    match value.as_str()
    {
      "false" => {},
      "local" => smoke_test_run( "_local_smoke_test", true ),
      "published" => {},
      _ =>
      {
        smoke_test_run( "_local_smoke_test", true );
      },
    }
  }
}

//

#[ test ]
fn published_smoke_test()
{
  if let Ok( value ) = std::env::var( "WITH_SMOKE" )
  {
    match value.as_str()
    {
      "false" | "0" => {},
      "local" => {},
      "published" => smoke_test_run( "_published_smoke_test", false ),
      _ =>
      {
        smoke_test_run( "_published_smoke_test", false );
      },
    }
  }
}
<|endoftext|>


<commit_before>use rustful::{
    Server,
    Handler,
    Context,
    Response,
    TreeRouter
};
use rustful::StatusCode;
use rustful::header::{
    ContentType,
    AccessControlAllowOrigin,
    AccessControlAllowMethods,
    AccessControlAllowHeaders,
    Host
};
use hyper::method::Method;
use pact_v1_matching::models::Pact;
use pact_v1_mock_server::start_mock_server;
use uuid::Uuid;
use std::error::Error;
use rustc_serialize::json::Json;

fn add_cors_headers(response: &mut Response) {
    response.headers_mut().set(AccessControlAllowOrigin::Any);
    response.headers_mut().set(AccessControlAllowMethods(vec![Method::Post]));
    response.headers_mut().set(AccessControlAllowHeaders(vec!["Content-Type".into()]));
}

fn start_provider(mut context: Context, mut response: Response) {
    add_cors_headers(&mut response);
    let json_result = context.body.read_json_body();
    match json_result {
        Ok(pact_json) => {
            let pact = Pact::from_json(&pact_json);
            let mock_server_id = Uuid::new_v4().to_string();
            match start_mock_server(mock_server_id.clone(), pact) {
                Ok(mock_server) => {
                    response.set_status(StatusCode::Ok);
                    let mock_server_json = Json::Object(btreemap!{
                        s!("id") => Json::String(mock_server_id),
                        s!("port") => Json::I64(mock_server as i64),
                    });
                    let json_response = Json::Object(btreemap!{ s!("mockServer") => mock_server_json });
                    response.send(json_response.to_string());
                },
                Err(msg) => {
                    response.set_status(StatusCode::BadRequest);
                    response.send(msg);
                }
            }
        },
        Err(err) => {
            error!("Could not parse pact json: {}", err);
            response.set_status(StatusCode::BadRequest);
            response.send(err.description());
        }
    }
}

pub fn start_command() {
    let my_router = insert_routes!{
        TreeRouter::new() => {
            Post: start_provider
        }
    };

    let server_result = Server {
        handlers: my_router,
        host: 8080.into(),
        ..Server::default()
    }.run();

    match server_result {
        Ok(server) => info!("Server started on port {}", server.socket.port()),
        Err(e) => panic!("could not start server: {}", e)
    }
}
<commit_msg>reponse should have a json content type<commit_after>use rustful::{
    Server,
    Handler,
    Context,
    Response,
    TreeRouter
};
use rustful::StatusCode;
use rustful::header::{
    ContentType,
    AccessControlAllowOrigin,
    AccessControlAllowMethods,
    AccessControlAllowHeaders,
    Host
};
use hyper::method::Method;
use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};
use pact_v1_matching::models::Pact;
use pact_v1_mock_server::start_mock_server;
use uuid::Uuid;
use std::error::Error;
use rustc_serialize::json::Json;

fn add_cors_headers(response: &mut Response) {
    response.headers_mut().set(AccessControlAllowOrigin::Any);
    response.headers_mut().set(AccessControlAllowMethods(vec![Method::Post]));
    response.headers_mut().set(AccessControlAllowHeaders(vec!["Content-Type".into()]));
}

fn start_provider(mut context: Context, mut response: Response) {
    add_cors_headers(&mut response);
    let json_result = context.body.read_json_body();
    match json_result {
        Ok(pact_json) => {
            let pact = Pact::from_json(&pact_json);
            let mock_server_id = Uuid::new_v4().to_string();
            match start_mock_server(mock_server_id.clone(), pact) {
                Ok(mock_server) => {
                    response.set_status(StatusCode::Ok);
                    response.headers_mut().set(
                        ContentType(Mime(TopLevel::Application, SubLevel::Json,
                                         vec![(Attr::Charset, Value::Utf8)]))
                    );
                    let mock_server_json = Json::Object(btreemap!{
                        s!("id") => Json::String(mock_server_id),
                        s!("port") => Json::I64(mock_server as i64),
                    });
                    let json_response = Json::Object(btreemap!{ s!("mockServer") => mock_server_json });
                    response.send(json_response.to_string());
                },
                Err(msg) => {
                    response.set_status(StatusCode::BadRequest);
                    response.send(msg);
                }
            }
        },
        Err(err) => {
            error!("Could not parse pact json: {}", err);
            response.set_status(StatusCode::BadRequest);
            response.send(err.description());
        }
    }
}

pub fn start_command() {
    let my_router = insert_routes!{
        TreeRouter::new() => {
            Post: start_provider
        }
    };

    let server_result = Server {
        handlers: my_router,
        host: 8080.into(),
        ..Server::default()
    }.run();

    match server_result {
        Ok(server) => info!("Server started on port {}", server.socket.port()),
        Err(e) => panic!("could not start server: {}", e)
    }
}
<|endoftext|>


<commit_before>use std::io::{Cursor};

use byteorder::{LittleEndian, WriteBytesExt, ReadBytesExt};

use mul_reader::{simple_from_vecs};
use art::{ArtReader, TileOrStatic, Art, Tile, Static, RunPair, STATIC_OFFSET};

#[test]
fn test_load_tile() {
    let mut data = Cursor::new(vec![]);
    data.write_u32::<LittleEndian>(0).unwrap();  // Header
    for _i in 0..1022 {
        data.write_u16::<LittleEndian>(0xFFFF).unwrap();
    }

    let mul_reader = simple_from_vecs(vec![
        data.into_inner(),
    ]);
    let mut reader = ArtReader::from_mul(mul_reader);
    match reader.read(0) {
        Ok(TileOrStatic::Tile(tile)) => {
            assert_eq!(tile.header, 0);
            assert_eq!(tile.image_data[0], 0xFFFF);
        },
        Ok(_) => {
            panic!("Got Static instead of Tile");
        },
        Err(err) => panic!("{}", err)
    };
}

#[test]
fn test_tile_to_32bit() {
    let tile = Tile {
        header: 0,
        image_data: [0xFFFF; 1022]
    };
    let (width, height, data) = tile.to_32bit();
    assert_eq!(width, 44);
    assert_eq!(height, 44);
    assert_eq!(data.len(), 44 * 44);

    // Check the first row
    for i in 0..44 {
        if i == 21 || i == 22 {
            assert_eq!(data[i], 0xFFFFFFFF);
        } else {
            assert_eq!(data[i], 0);
        }
    }

    // Check the middle row
    for i in 0..44 {
        assert_eq!(data[i + (22 * 44)], 0xFFFFFFFF);
    }
}

#[test]
#[cfg(feature = "use-sdl2")]
fn test_tile_to_surface() {
    let tile = Tile {
        header: 0,
        image_data: [0xFFFF; 1022]
    };
    let surface = tile.to_surface();
    assert_eq!(surface.width(), 44);
    assert_eq!(surface.height(), 44);
    let data = surface.without_lock().unwrap();
    assert_eq!(data.len(), 44 * 44 * 4);

    // Check the first row
    for i in 0..44 {
        if i == 21 || i == 22 {
            assert_eq!(data[(i * 4)], 0xFF);
            assert_eq!(data[(i * 4) + 1], 0xFF);
            assert_eq!(data[(i * 4) + 2], 0xFF);
            assert_eq!(data[(i * 4) + 3], 0xFF);
        } else {
            assert_eq!(data[(i * 4)], 0);
            assert_eq!(data[(i * 4) + 1], 0);
            assert_eq!(data[(i * 4) + 2], 0);
            assert_eq!(data[(i * 4) + 3], 0);
        }
    }

    // Check the middle row
    for i in 0..44 {
        assert_eq!(data[((i + (22 * 44)) * 4)], 0xFF);
        assert_eq!(data[((i + (22 * 44)) * 4) + 1], 0xFF);
        assert_eq!(data[((i + (22 * 44)) * 4) + 2], 0xFF);
        assert_eq!(data[((i + (22 * 44)) * 4) + 3], 0xFF);
    }
}

fn example_art_mul() -> ArtReader<Cursor<Vec<u8>>> {
    let mut data = Cursor::new(vec![]);

    data.write_u16::<LittleEndian>(0).unwrap();  //Size, unused
    data.write_u16::<LittleEndian>(1).unwrap();  //Trigger, unknown
    data.write_u16::<LittleEndian>(3).unwrap();  //Width in pixels
    data.write_u16::<LittleEndian>(3).unwrap();  //Height in pixels

    data.write_u16::<LittleEndian>(0).unwrap();  //Row 1 offset
    data.write_u16::<LittleEndian>(5).unwrap();  //Row 2 offset
    data.write_u16::<LittleEndian>(12).unwrap();  //Row 3 offset

    data.write_u16::<LittleEndian>(1).unwrap();  //Row 1, run 1 spacer
    data.write_u16::<LittleEndian>(1).unwrap();  //Row 1, run 1 number of pixels
    data.write_u16::<LittleEndian>(0xFFFF).unwrap();  //Row 1, run 1 data
    data.write_u32::<LittleEndian>(0).unwrap();  //Row 1 EOL

    data.write_u16::<LittleEndian>(0).unwrap();  //Row 2, run 1 spacer
    data.write_u16::<LittleEndian>(3).unwrap();  //Row 2, run 1 number of pixels
    data.write_u16::<LittleEndian>(0xFFFF).unwrap();  //Row 2, run 1 data
    data.write_u16::<LittleEndian>(0xFFFF).unwrap();  //Row 2, run 1 data
    data.write_u16::<LittleEndian>(0xFFFF).unwrap();  //Row 2, run 1 data
    data.write_u32::<LittleEndian>(0).unwrap();  //Row 2 EOL

    data.write_u16::<LittleEndian>(1).unwrap();  //Row 1, run 1 spacer
    data.write_u16::<LittleEndian>(1).unwrap();  //Row 1, run 1 number of pixels
    data.write_u16::<LittleEndian>(0xFFFF).unwrap();  //Row 1, run 1 data
    data.write_u32::<LittleEndian>(0).unwrap();  //Row 2 EOL

    let mut padded = vec![];
    for _i in 0..STATIC_OFFSET {
        padded.push(vec![]);
    }
    padded.push(data.into_inner());

    let mul_reader = simple_from_vecs(padded);
    ArtReader::from_mul(mul_reader)
}

#[test]
fn test_load_static() {
    let mut reader = example_art_mul();
    match reader.read(STATIC_OFFSET) {
        Ok(TileOrStatic::Static(stat)) => {
            assert_eq!(stat.size, 0);
            assert_eq!(stat.trigger, 1);
            assert_eq!(stat.width, 3);
            assert_eq!(stat.height, 3);
            let (width, height, data) = stat.to_32bit();
            assert_eq!(stat.width, width as u16);
            assert_eq!(stat.height, height as u16);
            assert_eq!(data, vec![
                0, 0xFFFFFFFF, 0,
                0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
                0, 0xFFFFFFFF, 0
            ]);
        },
        Ok(_) => {
            panic!("Got Tile instead of Static");
        },
        Err(err) => panic!("{}", err)
    };
}

#[test]
#[cfg(feature = "use-sdl2")]
fn test_static_to_surface() {
    let mut reader = example_art_mul();
    match reader.read(STATIC_OFFSET) {
        Ok(TileOrStatic::Static(stat)) => {
            let surface = stat.to_surface();
            assert_eq!(surface.width(), 3);
            assert_eq!(surface.height(), 3);
            let data = surface.without_lock().expect("Failed to get surface data");
            let expectation = [
                0, 0, 0, 0,           255, 255, 255, 255,   0, 0, 0, 0,
                255, 255, 255, 255,   255, 255, 255, 255,   255, 255, 255, 255,
                0, 0, 0, 0,           255, 255, 255, 255,   0, 0, 0, 0,
            ];
            for (left, right) in data.iter().zip(expectation.iter()) {
                assert_eq!(left, right);
            }
        },
        Ok(_) => {
            panic!("Got Tile instead of Static");
        },
        Err(err) => panic!("{}", err)
    };
}

/*#[test]
fn dump_art() {
    use mul_reader::MulWriter;
    use art::{Art, Tile};
    use std::io::FileMode;
    let dummy_tile = Tile {header: 0, image_data: [0xFFFF, ..1022]};
    let mut mul_writer = MulWriter::new(&Path::new("./testdata/test_art.idx"), &Path::new("./testdata/test_art.mul"), FileMode::Truncate).ok().expect("Can't open files for writing");

    let serialized = dummy_tile.serialize();

    for i in range(0, 0x4000u32) {
        mul_writer.append(&serialized, None, None).ok().expect("Can't write white tile");
    }
}*/
<commit_msg>Image support for Art Tiles<commit_after>use std::io::{Cursor};
use image::Pixel;

use byteorder::{LittleEndian, WriteBytesExt, ReadBytesExt};

use mul_reader::{simple_from_vecs};
use art::{ArtReader, TileOrStatic, Art, Tile, Static, RunPair, STATIC_OFFSET};

#[test]
fn test_load_tile() {
    let mut data = Cursor::new(vec![]);
    data.write_u32::<LittleEndian>(0).unwrap();  // Header
    for _i in 0..1022 {
        data.write_u16::<LittleEndian>(0xFFFF).unwrap();
    }

    let mul_reader = simple_from_vecs(vec![
        data.into_inner(),
    ]);
    let mut reader = ArtReader::from_mul(mul_reader);
    match reader.read(0) {
        Ok(TileOrStatic::Tile(tile)) => {
            assert_eq!(tile.header, 0);
            assert_eq!(tile.image_data[0], 0xFFFF);
        },
        Ok(_) => {
            panic!("Got Static instead of Tile");
        },
        Err(err) => panic!("{}", err)
    };
}

#[test]
fn test_tile_to_32bit() {
    let tile = Tile {
        header: 0,
        image_data: [0xFFFF; 1022]
    };
    let (width, height, data) = tile.to_32bit();
    assert_eq!(width, 44);
    assert_eq!(height, 44);
    assert_eq!(data.len(), 44 * 44);

    // Check the first row
    for i in 0..44 {
        if i == 21 || i == 22 {
            assert_eq!(data[i], 0xFFFFFFFF);
        } else {
            assert_eq!(data[i], 0);
        }
    }

    // Check the middle row
    for i in 0..44 {
        assert_eq!(data[i + (22 * 44)], 0xFFFFFFFF);
    }
}

#[test]
fn test_tile_to_image() {
    let tile = Tile {
        header: 0,
        image_data: [0xFFFF; 1022]
    };
    let image = tile.to_image();
    assert_eq!(image.width(), 44);
    assert_eq!(image.height(), 44);

    // Check the first row
    for i in 0..44 {
        if i == 21 || i == 22 {
            assert_eq!(image.get_pixel(i, 0).channels4(), (0xFF, 0xFF, 0xFF, 0xFF));
        } else {
            assert_eq!(image.get_pixel(i, 0).channels4(), (0, 0, 0, 0));
        }
    }

    // Check the middle row
    for i in 0..44 {
        assert_eq!(image.get_pixel(i, 22).channels4(), (0xFF, 0xFF, 0xFF, 0xFF));
    }
}

#[test]
#[cfg(feature = "use-sdl2")]
fn test_tile_to_surface() {
    let tile = Tile {
        header: 0,
        image_data: [0xFFFF; 1022]
    };
    let surface = tile.to_surface();
    assert_eq!(surface.width(), 44);
    assert_eq!(surface.height(), 44);
    let data = surface.without_lock().unwrap();
    assert_eq!(data.len(), 44 * 44 * 4);

    // Check the first row
    for i in 0..44 {
        if i == 21 || i == 22 {
            assert_eq!(data[(i * 4)], 0xFF);
            assert_eq!(data[(i * 4) + 1], 0xFF);
            assert_eq!(data[(i * 4) + 2], 0xFF);
            assert_eq!(data[(i * 4) + 3], 0xFF);
        } else {
            assert_eq!(data[(i * 4)], 0);
            assert_eq!(data[(i * 4) + 1], 0);
            assert_eq!(data[(i * 4) + 2], 0);
            assert_eq!(data[(i * 4) + 3], 0);
        }
    }

    // Check the middle row
    for i in 0..44 {
        assert_eq!(data[((i + (22 * 44)) * 4)], 0xFF);
        assert_eq!(data[((i + (22 * 44)) * 4) + 1], 0xFF);
        assert_eq!(data[((i + (22 * 44)) * 4) + 2], 0xFF);
        assert_eq!(data[((i + (22 * 44)) * 4) + 3], 0xFF);
    }
}

fn example_art_mul() -> ArtReader<Cursor<Vec<u8>>> {
    let mut data = Cursor::new(vec![]);

    data.write_u16::<LittleEndian>(0).unwrap();  //Size, unused
    data.write_u16::<LittleEndian>(1).unwrap();  //Trigger, unknown
    data.write_u16::<LittleEndian>(3).unwrap();  //Width in pixels
    data.write_u16::<LittleEndian>(3).unwrap();  //Height in pixels

    data.write_u16::<LittleEndian>(0).unwrap();  //Row 1 offset
    data.write_u16::<LittleEndian>(5).unwrap();  //Row 2 offset
    data.write_u16::<LittleEndian>(12).unwrap();  //Row 3 offset

    data.write_u16::<LittleEndian>(1).unwrap();  //Row 1, run 1 spacer
    data.write_u16::<LittleEndian>(1).unwrap();  //Row 1, run 1 number of pixels
    data.write_u16::<LittleEndian>(0xFFFF).unwrap();  //Row 1, run 1 data
    data.write_u32::<LittleEndian>(0).unwrap();  //Row 1 EOL

    data.write_u16::<LittleEndian>(0).unwrap();  //Row 2, run 1 spacer
    data.write_u16::<LittleEndian>(3).unwrap();  //Row 2, run 1 number of pixels
    data.write_u16::<LittleEndian>(0xFFFF).unwrap();  //Row 2, run 1 data
    data.write_u16::<LittleEndian>(0xFFFF).unwrap();  //Row 2, run 1 data
    data.write_u16::<LittleEndian>(0xFFFF).unwrap();  //Row 2, run 1 data
    data.write_u32::<LittleEndian>(0).unwrap();  //Row 2 EOL

    data.write_u16::<LittleEndian>(1).unwrap();  //Row 1, run 1 spacer
    data.write_u16::<LittleEndian>(1).unwrap();  //Row 1, run 1 number of pixels
    data.write_u16::<LittleEndian>(0xFFFF).unwrap();  //Row 1, run 1 data
    data.write_u32::<LittleEndian>(0).unwrap();  //Row 2 EOL

    let mut padded = vec![];
    for _i in 0..STATIC_OFFSET {
        padded.push(vec![]);
    }
    padded.push(data.into_inner());

    let mul_reader = simple_from_vecs(padded);
    ArtReader::from_mul(mul_reader)
}

#[test]
fn test_load_static() {
    let mut reader = example_art_mul();
    match reader.read(STATIC_OFFSET) {
        Ok(TileOrStatic::Static(stat)) => {
            assert_eq!(stat.size, 0);
            assert_eq!(stat.trigger, 1);
            assert_eq!(stat.width, 3);
            assert_eq!(stat.height, 3);
            let (width, height, data) = stat.to_32bit();
            assert_eq!(stat.width, width as u16);
            assert_eq!(stat.height, height as u16);
            assert_eq!(data, vec![
                0, 0xFFFFFFFF, 0,
                0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
                0, 0xFFFFFFFF, 0
            ]);
        },
        Ok(_) => {
            panic!("Got Tile instead of Static");
        },
        Err(err) => panic!("{}", err)
    };
}

#[test]
#[cfg(feature = "use-sdl2")]
fn test_static_to_surface() {
    let mut reader = example_art_mul();
    match reader.read(STATIC_OFFSET) {
        Ok(TileOrStatic::Static(stat)) => {
            let surface = stat.to_surface();
            assert_eq!(surface.width(), 3);
            assert_eq!(surface.height(), 3);
            let data = surface.without_lock().expect("Failed to get surface data");
            let expectation = [
                0, 0, 0, 0,           255, 255, 255, 255,   0, 0, 0, 0,
                255, 255, 255, 255,   255, 255, 255, 255,   255, 255, 255, 255,
                0, 0, 0, 0,           255, 255, 255, 255,   0, 0, 0, 0,
            ];
            for (left, right) in data.iter().zip(expectation.iter()) {
                assert_eq!(left, right);
            }
        },
        Ok(_) => {
            panic!("Got Tile instead of Static");
        },
        Err(err) => panic!("{}", err)
    };
}

/*#[test]
fn dump_art() {
    use mul_reader::MulWriter;
    use art::{Art, Tile};
    use std::io::FileMode;
    let dummy_tile = Tile {header: 0, image_data: [0xFFFF, ..1022]};
    let mut mul_writer = MulWriter::new(&Path::new("./testdata/test_art.idx"), &Path::new("./testdata/test_art.mul"), FileMode::Truncate).ok().expect("Can't open files for writing");

    let serialized = dummy_tile.serialize();

    for i in range(0, 0x4000u32) {
        mul_writer.append(&serialized, None, None).ok().expect("Can't write white tile");
    }
}*/
<|endoftext|>