diff --git a/server/src/engine/core/space.rs b/server/src/engine/core/space.rs index 6f251e51..2fc8b741 100644 --- a/server/src/engine/core/space.rs +++ b/server/src/engine/core/space.rs @@ -109,6 +109,9 @@ impl Space { pub fn empty() -> Self { Space::new_auto(Default::default(), SpaceMeta::with_env(into_dict! {})) } + pub fn empty_with_uuid(uuid: Uuid) -> Self { + Space::new_with_uuid(Default::default(), SpaceMeta::with_env(into_dict!()), uuid) + } #[inline(always)] pub fn new_auto(mns: IndexST, Model>, meta: SpaceMeta) -> Self { Self { diff --git a/server/src/engine/core/tests/ddl_space/alter.rs b/server/src/engine/core/tests/ddl_space/alter.rs index 4e58e648..65cb7e44 100644 --- a/server/src/engine/core/tests/ddl_space/alter.rs +++ b/server/src/engine/core/tests/ddl_space/alter.rs @@ -36,101 +36,112 @@ use crate::engine::{ #[test] fn alter_add_prop_env_var() { let gns = GlobalNS::empty(); - let uuid = super::exec_create_empty_verify(&gns, "create space myspace").unwrap(); - super::exec_alter_and_verify( + super::exec_create_alter( &gns, + "create space myspace", "alter space myspace with { env: { MY_NEW_PROP: 100 } }", |space| { - let space = space.unwrap(); assert_eq!( space, &Space::new_with_uuid( into_dict!(), SpaceMeta::with_env(into_dict! ("MY_NEW_PROP" => Datacell::new_uint(100))), - uuid + space.get_uuid() ) ); }, ) + .unwrap(); } #[test] fn alter_update_prop_env_var() { let gns = GlobalNS::empty(); - super::exec_create_and_verify( + let uuid = super::exec_create( &gns, "create space myspace with { env: { MY_NEW_PROP: 100 } }", |space| { assert_eq!( - space.unwrap().meta.env.read().get("MY_NEW_PROP").unwrap(), + space.meta.env.read().get("MY_NEW_PROP").unwrap(), &(Datacell::new_uint(100).into()) ) }, - ); - super::exec_alter_and_verify( + ) + .unwrap(); + super::exec_alter( &gns, "alter space myspace with { env: { MY_NEW_PROP: 200 } }", |space| { assert_eq!( - space.unwrap(), - &Space::new_auto( + space, + &Space::new_with_uuid( into_dict!(), - SpaceMeta::with_env(into_dict! ("MY_NEW_PROP" => Datacell::new_uint(200))) + SpaceMeta::with_env(into_dict! ("MY_NEW_PROP" => Datacell::new_uint(200))), + uuid, ) ) }, ) + .unwrap(); } #[test] fn alter_remove_prop_env_var() { let gns = GlobalNS::empty(); - super::exec_create_and_verify( + let uuid = super::exec_create( &gns, "create space myspace with { env: { MY_NEW_PROP: 100 } }", |space| { assert_eq!( - space.unwrap().meta.env.read().get("MY_NEW_PROP").unwrap(), + space.meta.env.read().get("MY_NEW_PROP").unwrap(), &(Datacell::new_uint(100).into()) ) }, - ); - super::exec_alter_and_verify( + ) + .unwrap(); + super::exec_alter( &gns, "alter space myspace with { env: { MY_NEW_PROP: null } }", |space| { assert_eq!( - space.unwrap(), - &Space::new_auto(into_dict!(), SpaceMeta::with_env(into_dict!())) + space, + &Space::new_with_uuid(into_dict!(), SpaceMeta::with_env(into_dict!()), uuid) ) }, ) + .unwrap(); } #[test] fn alter_nx() { let gns = GlobalNS::empty(); - super::exec_alter_and_verify( - &gns, - "alter space myspace with { env: { MY_NEW_PROP: 100 } }", - |space| assert_eq!(space.unwrap_err(), DatabaseError::DdlSpaceNotFound), - ) + assert_eq!( + super::exec_alter( + &gns, + "alter space myspace with { env: { MY_NEW_PROP: 100 } }", + |_| {}, + ) + .unwrap_err(), + DatabaseError::DdlSpaceNotFound + ); } #[test] fn alter_remove_all_env() { let gns = GlobalNS::empty(); - super::exec_create_and_verify( + let uuid = super::exec_create( &gns, "create space myspace with { env: { MY_NEW_PROP: 100 } }", |space| { assert_eq!( - space.unwrap().meta.env.read().get("MY_NEW_PROP").unwrap(), + space.meta.env.read().get("MY_NEW_PROP").unwrap(), &(Datacell::new_uint(100).into()) ) }, - ); - super::exec_alter_and_verify(&gns, "alter space myspace with { env: null }", |space| { - assert_eq!(space.unwrap(), &Space::empty()) + ) + .unwrap(); + super::exec_alter(&gns, "alter space myspace with { env: null }", |space| { + assert_eq!(space, &Space::empty_with_uuid(uuid)) }) + .unwrap(); } diff --git a/server/src/engine/core/tests/ddl_space/create.rs b/server/src/engine/core/tests/ddl_space/create.rs index a38ea866..e66f4926 100644 --- a/server/src/engine/core/tests/ddl_space/create.rs +++ b/server/src/engine/core/tests/ddl_space/create.rs @@ -36,13 +36,16 @@ use crate::engine::{ #[test] fn exec_create_space_simple() { let gns = GlobalNS::empty(); - super::exec_create_empty_verify(&gns, "create space myspace").unwrap(); + super::exec_create(&gns, "create space myspace", |spc| { + assert!(spc.models().read().is_empty()) + }) + .unwrap(); } #[test] fn exec_create_space_with_env() { let gns = GlobalNS::empty(); - super::exec_create_and_verify( + super::exec_create( &gns, r#" create space myspace with { @@ -53,34 +56,39 @@ fn exec_create_space_with_env() { "#, |space| { assert_eq!( - space.unwrap(), - &Space::new_auto( + space, + &Space::new_with_uuid( into_dict! {}, SpaceMeta::with_env(into_dict! { "MAX_MODELS" => Datacell::new_uint(100) - }) + }), + space.get_uuid() ) ); }, ) + .unwrap(); } #[test] fn exec_create_space_with_bad_env_type() { let gns = GlobalNS::empty(); - super::exec_create_and_verify(&gns, "create space myspace with { env: 100 }", |space| { - assert_eq!(space.unwrap_err(), DatabaseError::DdlSpaceBadProperty); - }); + assert_eq!( + super::exec_create(&gns, "create space myspace with { env: 100 }", |_| {}).unwrap_err(), + DatabaseError::DdlSpaceBadProperty + ); } #[test] fn exec_create_space_with_random_property() { let gns = GlobalNS::empty(); - super::exec_create_and_verify( - &gns, - "create space myspace with { i_am_blue_da_ba_dee: 100 }", - |space| { - assert_eq!(space.unwrap_err(), DatabaseError::DdlSpaceBadProperty); - }, + assert_eq!( + super::exec_create( + &gns, + "create space myspace with { i_am_blue_da_ba_dee: 100 }", + |_| {} + ) + .unwrap_err(), + DatabaseError::DdlSpaceBadProperty ); } diff --git a/server/src/engine/core/tests/ddl_space/mod.rs b/server/src/engine/core/tests/ddl_space/mod.rs index 3a1139dc..b33babf1 100644 --- a/server/src/engine/core/tests/ddl_space/mod.rs +++ b/server/src/engine/core/tests/ddl_space/mod.rs @@ -29,68 +29,46 @@ mod create; use crate::engine::{ core::{space::Space, GlobalNS}, + data::uuid::Uuid, error::DatabaseResult, - idx::STIndex, ql::{ - ast::{compile_test, Statement}, + ast::{self}, tests::lex_insecure as lex, }, }; -fn exec_verify( - gns: &GlobalNS, - query: &str, - mut exec: impl FnMut(&GlobalNS, Statement<'_>) -> (DatabaseResult<()>, Box), - mut verify: impl FnMut(DatabaseResult<&Space>), -) { - let tok = lex(query.as_bytes()).unwrap(); - let ast_node = compile_test(&tok).unwrap(); - let (res, space_name) = exec(gns, ast_node); - let rl = gns.spaces().read(); - let space_ref = rl.st_get(&space_name); - let r = res.map(|_| space_ref.unwrap()); - verify(r); -} - -/// Creates a space using the given tokens and allows the caller to verify it -fn exec_alter_and_verify(gns: &GlobalNS, tok: &str, verify: impl Fn(DatabaseResult<&Space>)) { - exec_verify( - gns, - tok, - |gns, stmt| { - let space = extract_safe!(stmt, Statement::AlterSpace(s) => s); - let space_name = space.space_name; - let r = Space::exec_alter(&gns, space); - (r, space_name.boxed_str()) - }, - verify, - ); +fn exec_create(gns: &GlobalNS, create: &str, verify: impl Fn(&Space)) -> DatabaseResult { + let tok = lex(create.as_bytes()).unwrap(); + let ast_node = + ast::parse_ast_node_full::(&tok[2..]).unwrap(); + let name = ast_node.space_name; + Space::exec_create(gns, ast_node)?; + gns.with_space(&name, |space| { + verify(space); + Ok(space.get_uuid()) + }) } -/// Creates a space using the given tokens and allows the caller to verify it -fn exec_create_and_verify(gns: &GlobalNS, tok: &str, verify: impl FnMut(DatabaseResult<&Space>)) { - exec_verify( - gns, - tok, - |gns, stmt| { - let space = extract_safe!(stmt, Statement::CreateSpace(s) => s); - let space_name = space.space_name; - let r = Space::exec_create(&gns, space); - (r, space_name.boxed_str()) - }, - verify, - ); +fn exec_alter(gns: &GlobalNS, alter: &str, verify: impl Fn(&Space)) -> DatabaseResult { + let tok = lex(alter.as_bytes()).unwrap(); + let ast_node = + ast::parse_ast_node_full::(&tok[2..]).unwrap(); + let name = ast_node.space_name; + Space::exec_alter(gns, ast_node)?; + gns.with_space(&name, |space| { + verify(space); + Ok(space.get_uuid()) + }) } -/// Creates an empty space with the given tokens -fn exec_create_empty_verify( +fn exec_create_alter( gns: &GlobalNS, - tok: &str, -) -> DatabaseResult { - let mut name = None; - self::exec_create_and_verify(gns, tok, |space| { - assert_eq!(space.unwrap(), &Space::empty()); - name = Some(space.unwrap().get_uuid()); - }); - Ok(name.unwrap()) + crt: &str, + alt: &str, + verify_post_alt: impl Fn(&Space), +) -> DatabaseResult { + let uuid_crt = exec_create(gns, crt, |_| {})?; + let uuid_alt = exec_alter(gns, alt, verify_post_alt)?; + assert_eq!(uuid_crt, uuid_alt); + Ok(uuid_alt) } diff --git a/server/src/engine/macros.rs b/server/src/engine/macros.rs index 13ba99ab..bb9ce76d 100644 --- a/server/src/engine/macros.rs +++ b/server/src/engine/macros.rs @@ -35,6 +35,7 @@ macro_rules! extract { } #[cfg(test)] +#[allow(unused_macros)] macro_rules! extract_safe { ($src:expr, $what:pat => $ret:expr) => { if let $what = $src { diff --git a/server/src/engine/storage/v1/inf/map.rs b/server/src/engine/storage/v1/inf/map.rs index aaeec366..f90b33f2 100644 --- a/server/src/engine/storage/v1/inf/map.rs +++ b/server/src/engine/storage/v1/inf/map.rs @@ -92,7 +92,10 @@ pub fn dec_dict( }; let mut dict = HashMap::with_capacity(size); while PM::meta_dec_entry_pretest(scanner) & (dict.len() != size) { - let md = dec_md::(scanner)?; + let md = unsafe { + // pretest + dec_md::(scanner)? + }; if PM::META_VERIFY_BEFORE_DEC && !md.pretest_src_for_object_dec(scanner) { return Err(SDSSError::InternalDecodeStructureCorrupted); } diff --git a/server/src/engine/storage/v1/inf/mod.rs b/server/src/engine/storage/v1/inf/mod.rs index dfb5345a..38e8448b 100644 --- a/server/src/engine/storage/v1/inf/mod.rs +++ b/server/src/engine/storage/v1/inf/mod.rs @@ -113,6 +113,7 @@ pub trait PersistObjectMD: Sized { unsafe fn dec_md_payload(scanner: &mut BufferedScanner) -> Option; } +/// Metadata for a simple size requirement pub struct SimpleSizeMD; impl PersistObjectMD for SimpleSizeMD { @@ -144,17 +145,21 @@ impl PersistObjectMD for VoidMetadata { } } -fn dec_md(scanner: &mut BufferedScanner) -> SDSSResult { - if Md::pretest_src_for_metadata_dec(scanner) { - unsafe { - match Md::dec_md_payload(scanner) { - Some(md) => Ok(md), - None => { - if Md::MD_DEC_INFALLIBLE { - impossible!() - } else { - Err(SDSSError::InternalDecodeStructureCorrupted) - } +/// Decode metadata +/// +/// ## Safety +/// unsafe because you need to set whether you've already verified the metadata or not +unsafe fn dec_md( + scanner: &mut BufferedScanner, +) -> SDSSResult { + if ASSUME_PRETEST_PASS || Md::pretest_src_for_metadata_dec(scanner) { + match Md::dec_md_payload(scanner) { + Some(md) => Ok(md), + None => { + if Md::MD_DEC_INFALLIBLE { + impossible!() + } else { + Err(SDSSError::InternalDecodeStructureCorrupted) } } } @@ -212,7 +217,10 @@ pub fn enc_self>(obj: &Obj) -> VecU8 { /// dec the object pub fn dec(scanner: &mut BufferedScanner) -> SDSSResult { if Obj::Metadata::pretest_src_for_metadata_dec(scanner) { - let md = dec_md::(scanner)?; + let md = unsafe { + // UNSAFE(@ohsaya): pretest + dec_md::(scanner)? + }; if Obj::ALWAYS_VERIFY_PAYLOAD_USING_MD && !md.pretest_src_for_object_dec(scanner) { return Err(SDSSError::InternalDecodeStructureCorrupted); } diff --git a/server/src/engine/storage/v1/inf/obj.rs b/server/src/engine/storage/v1/inf/obj.rs index 70376626..99689840 100644 --- a/server/src/engine/storage/v1/inf/obj.rs +++ b/server/src/engine/storage/v1/inf/obj.rs @@ -169,7 +169,10 @@ impl PersistObjectHlIO for Field { & (::Metadata::pretest_src_for_metadata_dec(scanner)) & !fin { - let layer_md = dec_md(scanner)?; + let layer_md = unsafe { + // UNSAFE(@ohsayan): pretest + dec_md::<_, true>(scanner)? + }; let l = Layer::pe_obj_hlio_dec(scanner, layer_md)?; fin = l.tag().tag_class() != TagClass::List; layers.push(l);