From 0a492f86495d290258807569da653630e72bcbcd Mon Sep 17 00:00:00 2001 From: Alik Aslanyan Date: Wed, 10 Apr 2019 22:05:14 +0400 Subject: [PATCH] =?UTF-8?q?Fix=20bugs=20related=20to=20not=20working=20set?= =?UTF-8?q?ters=20when=20objects=20where=20empty,=20imp=E2=80=A6=20(#79)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …lement few convenience methods. --- .travis.yml | 4 +- cpp/ffi.h | 2 + cpp/helper/moduleconfig.h | 2 +- cpp/main.cpp | 17 ++-- rust/Cargo.lock | 2 +- rust/Cargo.toml | 2 +- rust/src/ffi/ext.rs | 174 ++++++++++++++++++++++++++++++++++---- rust/src/ffi/mod.rs | 65 ++++++++------ rust/src/gc_json.rs | 2 +- scripting/grip.inc | 13 +++ 10 files changed, 228 insertions(+), 55 deletions(-) diff --git a/.travis.yml b/.travis.yml index afe29a5..4fd58c7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -85,10 +85,10 @@ script: before_deploy: - mkdir -p $TRAVIS_BUILD_DIR/deploy/addons/amxmodx/modules - mkdir -p $TRAVIS_BUILD_DIR/deploy/addons/amxmodx/configs -- mkdir -p $TRAVIS_BUILD_DIR/deploy/addons/amxmodx/scripting +- mkdir -p $TRAVIS_BUILD_DIR/deploy/addons/amxmodx/scripting/include - cp $TRAVIS_BUILD_DIR/build/release/*.so $TRAVIS_BUILD_DIR/deploy/addons/amxmodx/modules - cp $TRAVIS_BUILD_DIR/configs/* $TRAVIS_BUILD_DIR/deploy/addons/amxmodx/configs -- cp $TRAVIS_BUILD_DIR/scripting/* $TRAVIS_BUILD_DIR/deploy/addons/amxmodx/scripting +- cp $TRAVIS_BUILD_DIR/scripting/* $TRAVIS_BUILD_DIR/deploy/addons/amxmodx/scripting/include - cd $TRAVIS_BUILD_DIR/deploy - tar czf grip-${TRAVIS_TAG}-${TARGET}.tar.gz addons deploy: diff --git a/cpp/ffi.h b/cpp/ffi.h index 1e22ce9..a717780 100644 --- a/cpp/ffi.h +++ b/cpp/ffi.h @@ -8,6 +8,8 @@ extern "C" { +cell grip_body_from_json(const void *amx, cell value, bool pretty, cell recursion_limit); + cell grip_body_from_string(const void *amx, const char *str); cell grip_cancel_request(const void *amx, cell cancellation); diff --git a/cpp/helper/moduleconfig.h b/cpp/helper/moduleconfig.h index 623c7aa..5d43222 100644 --- a/cpp/helper/moduleconfig.h +++ b/cpp/helper/moduleconfig.h @@ -26,7 +26,7 @@ * to add multiple entries. */ #define MODULE_NAME "gRIP" -#define MODULE_VERSION "0.1.0 Beta" +#define MODULE_VERSION "0.1.1 Beta" #define MODULE_AUTHOR "Inline" #define MODULE_URL "https://github.com/in-line/grip" #define MODULE_LOGTAG "gRIP" diff --git a/cpp/main.cpp b/cpp/main.cpp index 6c0375a..86e7a87 100644 --- a/cpp/main.cpp +++ b/cpp/main.cpp @@ -183,7 +183,9 @@ cell AMX_NATIVE_CALL grip_json_parse_file_amxx(AMX *amx, cell *params) { ZERO_INIT_STACK_BUFFER(buffer, params[arg_buffer_size]); - cell ret = grip_json_parse_file(amx, MF_GetAmxString(amx, params[arg_file], 0, &dummy), &buffer[0], params[arg_buffer_size]); + cell ret = grip_json_parse_file(amx, + MF_BuildPathname("%s", MF_GetAmxString(amx, params[arg_file], 0, &dummy)), + &buffer[0], params[arg_buffer_size]); MF_SetAmxStringSafe(amx, params[arg_buffer], &buffer[0], params[arg_buffer_size]); @@ -568,7 +570,7 @@ cell AMX_NATIVE_CALL grip_json_serial_to_string_amxx(AMX *amx, cell *params) { cell AMX_NATIVE_CALL grip_json_serial_to_file_amxx(AMX *amx, cell *params) { enum { arg_count, arg_value, arg_file, arg_pretty, arg_recursion_limit }; return grip_json_serial_to_file(amx, params[arg_value], - MF_GetAmxString(amx, params[arg_file], 3, &dummy), + MF_BuildPathname("%s", MF_GetAmxString(amx, params[arg_file], 3, &dummy)), params[arg_pretty] != 0, params[arg_recursion_limit]); } @@ -579,6 +581,11 @@ cell AMX_NATIVE_CALL grip_json_validate_amxx(AMX *amx, cell *params) { return grip_json_validate(amx, params[arg_schema], params[arg_value]); } +cell AMX_NATIVE_CALL grip_body_from_json_amxx(AMX *amx, cell *params) { + enum { arg_count, arg_value, arg_pretty, arg_recursion_limit}; + return grip_body_from_json(amx, params[arg_value], params[arg_pretty] != 0, params[arg_recursion_limit]); +} + AMX_NATIVE_INFO grip_exports[] = { {"grip_request", grip_request_amxx}, {"grip_destroy_body", grip_destroy_body_amxx}, @@ -650,19 +657,17 @@ AMX_NATIVE_INFO grip_exports[] = { {"grip_json_serial_to_string", grip_json_serial_to_string_amxx}, {"grip_json_serial_to_file", grip_json_serial_to_file_amxx}, {"grip_json_validate", grip_json_validate_amxx}, + {"grip_body_from_json", grip_body_from_json_amxx}, {nullptr, nullptr} }; - void OnAmxxAttach() { MF_AddNatives(grip_exports); } void OnPluginsLoaded() { - char configFilePath[MAX_PATH]; - MF_BuildPathnameR(configFilePath, sizeof(configFilePath), "%s/grip.ini", MF_GetLocalInfo("amxx_configsdir", "addons/amxmodx/configs")); - grip_init(log_error, configFilePath); + grip_init(log_error, MF_BuildPathname("%s/grip.ini", MF_GetLocalInfo("amxx_configsdir", "addons/amxmodx/configs"))); } void OnPluginsUnloaded() { diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 95ef0a5..018a1bb 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -467,7 +467,7 @@ dependencies = [ [[package]] name = "grip-rust" -version = "0.1.0-beta" +version = "0.1.1-beta" dependencies = [ "bacon_rajan_cc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 7c87a69..f644aea 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grip-rust" -version = "0.1.0-beta" +version = "0.1.1-beta" authors = ["alik"] edition = "2018" build = "src/build.rs" diff --git a/rust/src/ffi/ext.rs b/rust/src/ffi/ext.rs index 6fffaa0..56ce746 100644 --- a/rust/src/ffi/ext.rs +++ b/rust/src/ffi/ext.rs @@ -185,15 +185,28 @@ macro_rules! try_to_get_json_object_value_rc_gc { }; } +macro_rules! try_to_get_json_object_value_or_insert_rc_gc { + ($amx:expr, $object:expr, $name:expr, $dot_notation:expr) => { + try_and_log_ffi!( + $amx, + try_to_get_json_value_gc!($amx, $object).index_selective_safe_or_insert_rc_gc( + try_and_log_ffi!($amx, str_from_ptr($name)), + $dot_notation, + Some(InnerValue::Null) + ) + ) + }; +} + macro_rules! try_to_get_json_object_value_gc { ($amx:expr, $object:expr, $name:expr, $dot_notation:expr) => {{ try_to_get_json_object_value_rc_gc!($amx, $object, $name, $dot_notation).borrow() }}; } -macro_rules! try_to_get_json_object_value_gc_mut { +macro_rules! try_to_get_json_object_value_gc_or_insert_mut { ($amx:expr, $object:expr, $name:expr, $dot_notation:expr) => { - (&*try_to_get_json_object_value_rc_gc!($amx, $object, $name, $dot_notation) + (&*try_to_get_json_object_value_or_insert_rc_gc!($amx, $object, $name, $dot_notation) as &RefCell) .borrow_mut() }; @@ -210,17 +223,6 @@ macro_rules! try_to_get_json_object_value { }}; } -macro_rules! try_to_get_json_object_value_mut { - ($amx:expr, $object:expr, $name:expr, $dot_notation:expr) => {{ - gc_borrow_inner_mut!(try_to_get_json_object_value_gc_mut!( - $amx, - $object, - $name, - $dot_notation - )) - }}; -} - macro_rules! try_to_get_json_array { ($amx:expr, $array:expr) => { match &try_to_get_json_value!($amx, $array) { @@ -269,11 +271,23 @@ use std::rc::Rc; pub trait ValueExt<'a> { fn dot_index_safe_rc_gc(&'a self, name: &str) -> Result>>; + fn dot_index_safe_or_insert_rc_gc( + &'a self, + name: &str, + default: Option, + ) -> Result>>; fn index_selective_safe_rc_gc( &'a self, name: &str, dot_notation: bool, ) -> Result>>; + + fn index_selective_safe_or_insert_rc_gc( + &'a self, + name: &str, + dot_notation: bool, + default: Option, + ) -> Result>>; } impl<'a> ValueExt<'a> for GCValue { @@ -301,6 +315,90 @@ impl<'a> ValueExt<'a> for GCValue { Ok(it.chain_err(|| "Name is invalid")?) } + fn dot_index_safe_or_insert_rc_gc( + &'a self, + name: &str, + default: Option, + ) -> Result>> { + let mut it: Option>> = None; + let names = name.split('.').collect::>(); + let len = names.len(); + for (default_to_insert, element) in { + names.into_iter().enumerate().map(|(index, string)| { + ( + if index == len - 1 { + default.clone() + } else { + None + }, + string, + ) + }) + } { + if element.is_empty() { + bail!("Double/Empty separator in `{}`", name); + } + + // Same as bounds checked index. + if let Some(it_raw) = it { + let it_raw: &RefCell<_> = it_raw.borrow(); + it = Some( + it_raw + .borrow_mut() + .index_selective_safe_or_insert_rc_gc(element, false, default_to_insert)? + .clone(), + ); + } else { + it = Some( + self.index_selective_safe_or_insert_rc_gc(element, false, default_to_insert)? + .clone(), + ); + } + } + + Ok(it.chain_err(|| "Name is invalid")?) + } + + fn index_selective_safe_or_insert_rc_gc( + &'a self, + name: &str, + dot_notation: bool, + default: Option, + ) -> Result>> { + if dot_notation { + self.dot_index_safe_or_insert_rc_gc(name, default) + } else { + match &mut self.borrow_inner_ref_mut() as &mut InnerValue { + InnerValue::Object(m) => match { + match m.get_mut(name) { + None => { + if let Some(default) = default { + m.insert( + name.to_owned(), + Rc::new(RefCell::new(GCValue::new(default))), + ); + m.get_mut(name) + } else { + None + } + } + v => v, + } + } { + Some(target) => Ok(target.clone()), + None => bail!( + "Can't index json using `{}`, because json doesn't contain it", + name + ), + }, + _ => bail!( + "Can't index json using `{}` json stops is not object.", + name + ), + } + } + } + fn index_selective_safe_rc_gc( &'a self, name: &str, @@ -312,7 +410,7 @@ impl<'a> ValueExt<'a> for GCValue { match &self.borrow_inner_ref() as &InnerValue { InnerValue::Object(m) => match m.get(name) { Some(target) => Ok(target.clone()), - _ => bail!( + None => bail!( "Can't index json using `{}`, because json doesn't contain it", name ), @@ -366,7 +464,9 @@ mod tests { fn gc_to_json(v: Rc>) -> Value { let value: &RefCell<_> = v.borrow(); - (*gc_borrow_inner!(value.borrow())).clone().into_with_recursion_limit(2) + (*gc_borrow_inner!(value.borrow())) + .clone() + .into_with_recursion_limit(2) } assert_eq!( @@ -391,6 +491,50 @@ mod tests { assert!(gc_to_json(json.index_selective_safe_rc_gc("a", false).unwrap()).is_object()); assert!(json.index_selective_safe_rc_gc("a.b.c", false).is_err()); + + assert_eq!( + gc_to_json( + json.index_selective_safe_or_insert_rc_gc("a.b", true, None) + .unwrap() + ) + .as_u64() + .unwrap(), + 123 + ); + assert!(json + .index_selective_safe_or_insert_rc_gc("a.b.c", true, None) + .is_err()); + assert!(json + .index_selective_safe_or_insert_rc_gc("a..", true, None) + .is_err()); + assert!(gc_to_json( + json.index_selective_safe_or_insert_rc_gc("a", true, None) + .unwrap() + ) + .is_object()); + + assert!(gc_to_json( + json.index_selective_safe_or_insert_rc_gc("a", false, None) + .unwrap() + ) + .is_object()); + assert!(json + .index_selective_safe_or_insert_rc_gc("a.b.c", false, None) + .is_err()); + + assert!(json + .index_selective_safe_or_insert_rc_gc("a.d.d", false, None) + .is_err()); + + assert!(gc_to_json( + json.index_selective_safe_or_insert_rc_gc("a.d", true, Some(InnerValue::Null)) + .unwrap() + ) + .is_null()); + + assert!(json + .index_selective_safe_or_insert_rc_gc("a.d.d", false, None) + .is_err()); } } diff --git a/rust/src/ffi/mod.rs b/rust/src/ffi/mod.rs index 722282d..a4b5abd 100644 --- a/rust/src/ffi/mod.rs +++ b/rust/src/ffi/mod.rs @@ -1208,7 +1208,7 @@ pub unsafe extern "C" fn grip_json_object_set_value( try_and_log_ffi!( amx, catch_unwind(|| { - *try_to_get_json_object_value_gc_mut!(amx, object, name, dot_notation) = + *try_to_get_json_object_value_gc_or_insert_mut!(amx, object, name, dot_notation) = try_to_get_json_value_gc!(amx, value).clone(); 1 }) @@ -1226,21 +1226,12 @@ pub unsafe extern "C" fn grip_json_object_set_string( string: *const c_char, dot_notation: bool, ) -> Cell { - match &mut try_to_get_json_object_value_mut!(amx, object, name, dot_notation) { - InnerValue::String(s) => { - *s = try_and_log_ffi!( - amx, - str_from_ptr(string).chain_err(|| ffi_error("Can't create UTF-8 string")) - ) - .to_owned(); - - 1 - } - v => unconditionally_log_error!( + *try_to_get_json_object_value_gc_or_insert_mut!(amx, object, name, dot_notation) = + gc_json!(try_and_log_ffi!( amx, - ffi_error(format!("Object at index is not string: {:?}", v)) - ), - } + str_from_ptr(string).chain_err(|| ffi_error("Can't create UTF-8 string")) + )); + 1 } #[no_mangle] @@ -1251,16 +1242,9 @@ pub unsafe extern "C" fn grip_json_object_set_number( number: Cell, dot_notation: bool, ) -> Cell { - match &mut try_to_get_json_object_value_mut!(amx, object, name, dot_notation) { - InnerValue::Number(n) => { - *n = number.into(); - 1 - } - v => unconditionally_log_error!( - amx, - ffi_error(format!("Object at index is not number: {:?}", v)) - ), - } + *try_to_get_json_object_value_gc_or_insert_mut!(amx, object, name, dot_notation) = + gc_json!(number); + 1 } #[no_mangle] @@ -1271,7 +1255,8 @@ pub unsafe extern "C" fn grip_json_object_set_float( number: f32, dot_notation: bool, ) -> Cell { - *try_to_get_json_object_value_gc_mut!(amx, object, name, dot_notation) = gc_json!(number); + *try_to_get_json_object_value_gc_or_insert_mut!(amx, object, name, dot_notation) = + gc_json!(number); 1 } @@ -1283,7 +1268,8 @@ pub unsafe extern "C" fn grip_json_object_set_bool( value: bool, dot_notation: bool, ) -> Cell { - *try_to_get_json_object_value_gc_mut!(amx, object, name, dot_notation) = gc_json!(value); + *try_to_get_json_object_value_gc_or_insert_mut!(amx, object, name, dot_notation) = + gc_json!(value); 1 } @@ -1294,7 +1280,8 @@ pub unsafe extern "C" fn grip_json_object_set_null( name: *const c_char, dot_notation: bool, ) -> Cell { - *try_to_get_json_object_value_gc_mut!(amx, object, name, dot_notation) = gc_json!(null); + *try_to_get_json_object_value_gc_or_insert_mut!(amx, object, name, dot_notation) = + gc_json!(null); 1 } @@ -1469,3 +1456,25 @@ pub unsafe extern "C" fn grip_json_validate(amx: *const c_void, schema: Cell, va 1 } } + +#[no_mangle] +pub unsafe extern "C" fn grip_body_from_json( + amx: *const c_void, + value: Cell, + pretty: bool, + recursion_limit: Cell, +) -> Cell { + get_module_mut().bodies_handles.insert_with_unique_id( + try_and_log_ffi!( + amx, + serialize_to_string( + &try_to_get_json_value!(amx, value) + .clone() + .into_with_recursion_limit(try_as_usize!(amx, recursion_limit)), + pretty, + true + ) + ) + .into_bytes(), + ) +} diff --git a/rust/src/gc_json.rs b/rust/src/gc_json.rs index 52a91e1..2725d0a 100644 --- a/rust/src/gc_json.rs +++ b/rust/src/gc_json.rs @@ -42,7 +42,7 @@ impl GCValue { (&*self.0 as &RefCell).borrow() } - pub fn borrow_inner_ref_mut(&mut self) -> RefMut { + pub fn borrow_inner_ref_mut(&self) -> RefMut { (&*self.0 as &RefCell).borrow_mut() } diff --git a/scripting/grip.inc b/scripting/grip.inc index 7c462d9..b976686 100644 --- a/scripting/grip.inc +++ b/scripting/grip.inc @@ -194,6 +194,19 @@ native grip_is_request_active(GripRequestCancellation:request); */ native GripBody:grip_body_from_string(str[]); +/** + * Creates new body handle from string + * + * @note Body should be destroyed with the relevant call. + * + * @param str Zero terminated string from which body should be created + * @param pretty True to format pretty JSON string, false to not + * @param recursion_limit Limit of the internal recursion + * + * @return Newly crated body handle + */ +native GripBody:grip_body_from_json(GripJSONValue:value, bool:pretty = false, recursion_limit = 100); + /** * Destroys body handle *