wasm-link 0.4.1

A WebAssembly plugin runtime based around Wasmtime intended for building fully modular applications
Documentation
use std::collections::HashMap ;

use crate::cardinality::{ Any, AtLeastOne, AtMostOne, Cardinality, ExactlyOne };
use crate::{ Val, nem };



#[test]
fn exactly_one_maps_and_gets() {
	let value = ExactlyOne( "plugin".to_string(), 10_u32 );
	let mapped = value.map(| id, value | format!( "{id}:{value}" ));
	assert_eq!( mapped.0, "plugin" );
	assert_eq!( mapped.1, "plugin:10" );
	assert_eq!( mapped.get( &"plugin".to_string() ), Some( &"plugin:10".to_string() ));

	let value = ExactlyOne( "plugin".to_string(), 10_u32 );
	let mapped = futures::executor::block_on(
		value.map_async(| id, value | async move { format!( "{id}:{value}" )})
	);
	assert_eq!( mapped.0, "plugin" );
	assert_eq!( mapped.1, "plugin:10" );
}

#[test]
#[cfg(debug_assertions)]
#[should_panic( expected = "singleton cardinality id mismatch" )]
fn exactly_one_rejects_a_mismatched_id_in_debug_builds() {
	let value = ExactlyOne( "plugin".to_string(), 10_u32 );
	let _ = value.get( &"other".to_string() );
}

#[test]
fn at_most_one_maps_none_and_some() {
	let none: AtMostOne<String, u32> = AtMostOne( None );
	let mapped_none = none.map(| _, value | value + 1 );
	assert!( mapped_none.0.is_none() );
	assert_eq!( mapped_none.get( &"plugin".to_string() ), None );

	let none: AtMostOne<String, u32> = AtMostOne( None );
	assert!( none.map_mut(| value | value + 1 ).0.is_none() );

	let some = AtMostOne( Some(( "plugin".to_string(), 3_u32 )));
	let mapped_some = some.map(| _, value | value + 1 );
	assert_eq!( mapped_some.0, Some(( "plugin".to_string(), 4 )));
	assert_eq!( mapped_some.get( &"plugin".to_string() ), Some( &4 ));

	let some = AtMostOne( Some(( "plugin".to_string(), 3_u32 )));
	assert_eq!( some.map_mut(| value | value + 1 ).0, Some(( "plugin".to_string(), 4 )));

	let none: AtMostOne<String, u32> = AtMostOne( None );
	assert!( futures::executor::block_on(
		none.map_async(| _, value | async move { value + 1 })
	).0.is_none() );
	let some = AtMostOne( Some(( "plugin".to_string(), 3_u32 )));
	assert_eq!( futures::executor::block_on(
		some.map_async(| _, value | async move { value + 1 })
	).0, Some(( "plugin".to_string(), 4 )));
}

#[test]
#[cfg(debug_assertions)]
#[should_panic( expected = "singleton cardinality id mismatch" )]
fn at_most_one_rejects_a_mismatched_id_in_debug_builds() {
	let value = AtMostOne( Some(( "plugin".to_string(), 10_u32 )));
	let _ = value.get( &"other".to_string() );
}

#[test]
fn at_least_one_maps_and_gets() {
	let values = AtLeastOne( nem! { "a".to_string() => 1_u32, "b".to_string() => 2_u32 } );
	let mapped = values.map(| _, value | value * 2 );
	assert_eq!( mapped.get( &"a".to_string() ), Some( &2 ));
	assert_eq!( mapped.get( &"b".to_string() ), Some( &4 ));

	let values = AtLeastOne( nem! { "a".to_string() => 1_u32, "b".to_string() => 2_u32 } );
	let mapped = futures::executor::block_on(
		values.map_async(| _, value | async move { value * 2 })
	);
	assert_eq!( mapped.get( &"a".to_string() ), Some( &2 ));
	assert_eq!( mapped.get( &"b".to_string() ), Some( &4 ));

	let values = AtLeastOne( nem! { "a".to_string() => 1_u32, "b".to_string() => 2_u32 } );
	let mapped = values.map_mut(| value | value * 2 );
	assert_eq!( mapped.get( &"a".to_string() ), Some( &2 ));
	assert_eq!( mapped.get( &"b".to_string() ), Some( &4 ));
}

#[test]
fn any_maps_and_gets() {
	let values = Any( HashMap::from([
		( "a".to_string(), 1_u32 ),
		( "b".to_string(), 2_u32 ),
	]));
	let mapped = values.map(| _, value | value + 10 );
	assert_eq!( mapped.get( &"a".to_string() ), Some( &11 ));
	assert_eq!( mapped.get( &"b".to_string() ), Some( &12 ));

	let values = Any( HashMap::from([
		( "a".to_string(), 1_u32 ),
		( "b".to_string(), 2_u32 ),
	]));
	let mapped = futures::executor::block_on(
		values.map_async(| _, value | async move { value + 10 })
	);
	assert_eq!( mapped.get( &"a".to_string() ), Some( &11 ));
	assert_eq!( mapped.get( &"b".to_string() ), Some( &12 ));
}

#[test]
fn exactly_one_into_val() {
	let val = Val::from( ExactlyOne( "id".to_string(), Val::U32( 7 )));
	assert!( matches!( val, Val::Tuple( items ) if
		items.len() == 2
		&& matches!( &items[0], Val::String( id ) if id == "id" )
		&& matches!( &items[1], Val::U32( 7 ))
	));
}

#[test]
fn at_most_one_into_val() {
	let none = Val::from( AtMostOne::<String, Val>( None ));
	assert!( matches!( none, Val::Option( None )));

	let some = Val::from( AtMostOne( Some(( "id".to_string(), Val::U32( 1 )))));
	assert!( matches!( some, Val::Option( Some( boxed )) if
		matches!( &*boxed, Val::Tuple( items ) if
			items.len() == 2
			&& matches!( &items[0], Val::String( id ) if id == "id" )
			&& matches!( &items[1], Val::U32( 1 ))
		)
	));
}

#[test]
fn at_least_one_into_val() {
	let val = Val::from( AtLeastOne( nem! { "a".to_string() => Val::U32( 1 ) }));
	assert!( matches!( val, Val::Map( items ) if
		items.len() == 1
		&& matches!( &items[0], ( Val::String( id ), Val::U32( 1 )) if id == "a" )
	));
}

#[test]
fn any_into_val() {
	let val = Val::from( Any( HashMap::from([
		( "a".to_string(), Val::U32( 1 )),
		( "b".to_string(), Val::U32( 2 )),
	])));
	assert!( matches!( val, Val::Map( items ) if
		items.len() == 2
		&& items.iter().any(|item|
			matches!( item, ( Val::String( id ), Val::U32( 1 )) if id == "a" )
		)
		&& items.iter().any(|item|
			matches!( item, ( Val::String( id ), Val::U32( 2 )) if id == "b" )
		)
	));
}