shipyard 0.11.2

Entity Component System
Documentation
use core::any::type_name;
use shipyard::advanced::StorageId;
use shipyard::error;
use shipyard::views::{
    UniqueOrDefaultView, UniqueOrDefaultViewMut, UniqueOrInitView, UniqueOrInitViewMut,
};
use shipyard::*;

#[derive(Default, Debug, PartialEq)]
struct USIZE(usize);
impl Component for USIZE {
    type Tracking = track::Untracked;
}
impl Unique for USIZE {}

#[test]
fn unique_storage() {
    let world = World::new();
    world.add_unique(USIZE(0));

    world.run(|mut x: UniqueViewMut<USIZE>| {
        x.0 += 1;
    });
    world.run(|x: UniqueView<USIZE>| {
        assert_eq!(x.0, 1);
    });

    world.remove_unique::<USIZE>().unwrap();

    if let Some(get_error) = world.borrow::<UniqueViewMut<USIZE>>().err() {
        assert_eq!(
            get_error,
            shipyard::error::GetStorage::MissingStorage {
                name: Some(type_name::<UniqueStorage<USIZE>>()),
                id: StorageId::of::<UniqueStorage<USIZE>>(),
            }
        );
    } else {
        panic!()
    }
}

#[test]
fn not_unique_storage() {
    let world = World::new();

    match world.borrow::<UniqueView<USIZE>>().err() {
        Some(get_storage) => assert_eq!(
            get_storage,
            shipyard::error::GetStorage::MissingStorage {
                name: Some(type_name::<UniqueStorage<USIZE>>()),
                id: StorageId::of::<UniqueStorage<USIZE>>(),
            }
        ),
        _ => panic!(),
    }

    match world.borrow::<UniqueViewMut<USIZE>>().err() {
        Some(get_storage) => assert_eq!(
            get_storage,
            shipyard::error::GetStorage::MissingStorage {
                name: Some(type_name::<UniqueStorage<USIZE>>()),
                id: StorageId::of::<UniqueStorage<USIZE>>(),
            }
        ),
        _ => panic!(),
    }

    match world.remove_unique::<USIZE>().err() {
        Some(error::UniqueRemove::MissingUnique(name)) => assert_eq!(name, type_name::<USIZE>()),
        _ => panic!(),
    }
}

#[cfg(feature = "thread_local")]
#[test]
fn non_send() {
    struct NonSendStruct {
        value: usize,
        _phantom: core::marker::PhantomData<*const ()>,
    }
    unsafe impl Sync for NonSendStruct {}
    impl Component for NonSendStruct {
        type Tracking = track::Untracked;
    }
    impl Unique for NonSendStruct {}

    let world = World::default();
    world.add_unique_non_send(NonSendStruct {
        value: 0,
        _phantom: core::marker::PhantomData,
    });

    world.run(|mut x: borrow::NonSend<UniqueViewMut<NonSendStruct>>| {
        x.value += 1;
    });
    world.run(|x: borrow::NonSend<UniqueView<NonSendStruct>>| {
        assert_eq!(x.value, 1);
    });
}

#[cfg(feature = "thread_local")]
#[test]
fn non_sync() {
    struct NonSyncStruct {
        value: usize,
        _phantom: core::marker::PhantomData<*const ()>,
    }
    unsafe impl Send for NonSyncStruct {}
    impl Component for NonSyncStruct {
        type Tracking = track::Untracked;
    }
    impl Unique for NonSyncStruct {}

    let world = World::default();
    world.add_unique_non_sync(NonSyncStruct {
        value: 0,
        _phantom: core::marker::PhantomData,
    });

    world.run(|mut x: borrow::NonSync<UniqueViewMut<NonSyncStruct>>| {
        x.value += 1;
    });
    world.run(|x: borrow::NonSync<UniqueView<NonSyncStruct>>| {
        assert_eq!(x.value, 1);
    });
}

#[cfg(feature = "thread_local")]
#[test]
fn non_send_sync() {
    struct NonSendSyncStruct {
        value: usize,
        _phantom: core::marker::PhantomData<*const ()>,
    }
    impl Component for NonSendSyncStruct {
        type Tracking = track::Untracked;
    }
    impl Unique for NonSendSyncStruct {}

    let world = World::default();
    world.add_unique_non_send_sync(NonSendSyncStruct {
        value: 0,
        _phantom: core::marker::PhantomData,
    });

    world.run(
        |mut x: borrow::NonSendSync<UniqueViewMut<NonSendSyncStruct>>| {
            x.value += 1;
        },
    );
    world.run(|x: borrow::NonSendSync<UniqueView<NonSendSyncStruct>>| {
        assert_eq!(x.value, 1);
    });
}

#[test]
#[cfg(feature = "thread_local")]
fn non_send_remove() {
    let world: &'static World = Box::leak(Box::new(World::new()));

    world.add_unique_non_send(USIZE(0));

    std::thread::spawn(move || {
        if let Some(shipyard::error::UniqueRemove::StorageBorrow(infos)) =
            world.remove_unique::<USIZE>().err()
        {
            assert_eq!(
                infos,
                (type_name::<USIZE>(), shipyard::error::Borrow::WrongThread)
            );
        } else {
            panic!()
        }
    })
    .join()
    .unwrap();
}

#[test]
fn unique_or_default() {
    let world = World::new();

    world.run(|u: UniqueOrDefaultView<USIZE>| assert_eq!(*u, USIZE(0)));
}

#[test]
fn unique_or_default_mut() {
    let world = World::new();

    world.run(|mut u: UniqueOrDefaultViewMut<USIZE>| {
        u.0 += 1;
        assert_eq!(*u, USIZE(1))
    });
}

#[test]
fn unique_or_init() {
    let world = World::new();

    world.run(|u: UniqueOrInitView<USIZE>| {
        assert_eq!(**u.get_or_init(|| USIZE(10)).unwrap(), USIZE(10))
    });

    world.run(|u: UniqueOrInitView<USIZE>| assert_eq!(**u.get().unwrap(), USIZE(10)));
}

#[test]
fn unique_or_init_mut() {
    let world = World::new();

    world.run(|u: UniqueOrInitViewMut<USIZE>| {
        assert_eq!(**u.get_or_init(|| USIZE(10)).unwrap(), USIZE(10))
    });

    world.run(|mut u: UniqueOrInitViewMut<USIZE>| u.get_mut().unwrap().0 += 1);

    world.run(|u: UniqueOrInitViewMut<USIZE>| assert_eq!(**u.get().unwrap(), USIZE(11)));
}