shipyard 0.6.2

Entity Component System
Documentation
use core::any::type_name;
use shipyard::error;
use shipyard::*;

struct USIZE(usize);
impl Component for USIZE {
    type Tracking = track::Untracked;
}
impl Unique for USIZE {
    type Tracking = track::Untracked;
}

#[test]
fn unique_storage() {
    let world = World::new_with_custom_lock::<parking_lot::RawRwLock>();
    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>>().into()),
                id: StorageId::of::<UniqueStorage<USIZE>>(),
            }
        );
    } else {
        panic!()
    }
}

#[test]
fn not_unique_storage() {
    let world = World::new_with_custom_lock::<parking_lot::RawRwLock>();

    match world.borrow::<UniqueView<USIZE>>().err() {
        Some(get_storage) => assert_eq!(
            get_storage,
            shipyard::error::GetStorage::MissingStorage {
                name: Some(type_name::<UniqueStorage<USIZE>>().into()),
                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>>().into()),
                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 {
        type Tracking = track::Untracked;
    }

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

    world.run(|mut x: NonSend<UniqueViewMut<NonSendStruct>>| {
        x.value += 1;
    });
    world.run(|x: 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 {
        type Tracking = track::Untracked;
    }

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

    world.run(|mut x: NonSync<UniqueViewMut<NonSyncStruct>>| {
        x.value += 1;
    });
    world.run(|x: 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 {
        type Tracking = track::Untracked;
    }

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

    world.run(|mut x: NonSendSync<UniqueViewMut<NonSendSyncStruct>>| {
        x.value += 1;
    });
    world.run(|x: 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_with_custom_lock::<
        parking_lot::RawRwLock,
    >()));

    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();
}