diff --git a/bindings/c/cbindgen.toml b/bindings/c/cbindgen.toml index aafbb6d5f107..66296943c8d0 100644 --- a/bindings/c/cbindgen.toml +++ b/bindings/c/cbindgen.toml @@ -48,3 +48,6 @@ sys_includes = ["stdint.h", "stddef.h", "stdbool.h"] [parse] include = ["opendal"] parse_deps = true + +[fn] +deprecated_with_note = "__attribute__((deprecated({})))" diff --git a/bindings/c/include/opendal.h b/bindings/c/include/opendal.h index 8eeacf7c5121..03e3eda759ba 100644 --- a/bindings/c/include/opendal.h +++ b/bindings/c/include/opendal.h @@ -361,6 +361,27 @@ typedef struct opendal_result_is_exist { struct opendal_error *error; } opendal_result_is_exist; +/** + * \brief The result type returned by opendal_operator_exists(). + * + * The result type for opendal_operator_exists(), the field `exists` + * contains whether the path exists, and the field `error` contains the + * corresponding error. If successful, the `error` field is null. + * + * \note If the opendal_operator_exists() fails, the `exists` field + * will be set to false. + */ +typedef struct opendal_result_exists { + /** + * Whether the path exists + */ + bool exists; + /** + * The error, if ok, it is null + */ + struct opendal_error *error; +} opendal_result_exists; + /** * \brief The result type returned by opendal_operator_stat(). * @@ -1025,9 +1046,52 @@ struct opendal_error *opendal_operator_delete(const struct opendal_operator *op, * * * If the `path` points to NULL, this function panics, i.e. exits with information */ +__attribute__((deprecated("Use opendal_operator_exists() instead."))) struct opendal_result_is_exist opendal_operator_is_exist(const struct opendal_operator *op, const char *path); +/** + * \brief Check whether the path exists. + * + * If the operation succeeds, no matter the path exists or not, + * the error should be a nullptr. Otherwise, the field `exists` + * is filled with false, and the error is set + * + * @param op The opendal_operator created previously + * @param path The path you want to check existence + * @see opendal_operator + * @see opendal_result_exists + * @see opendal_error + * @return Returns opendal_result_exists, the `exists` field contains whether the path exists. + * However, it the operation fails, the `exists` will contain false and the error will be set. + * + * # Example + * + * ```C + * // .. you previously wrote some data to path "/mytest/obj" + * opendal_result_exists e = opendal_operator_exists(op, "/mytest/obj"); + * assert(e.error == NULL); + * assert(e.exists); + * + * // but you previously did **not** write any data to path "/yourtest/obj" + * opendal_result_exists e = opendal_operator_exists(op, "/yourtest/obj"); + * assert(e.error == NULL); + * assert(!e.exists); + * ``` + * + * # Safety + * + * It is **safe** under the cases below + * * The memory pointed to by `path` must contain a valid nul terminator at the end of + * the string. + * + * # Panic + * + * * If the `path` points to NULL, this function panics, i.e. exits with information + */ +struct opendal_result_exists opendal_operator_exists(const struct opendal_operator *op, + const char *path); + /** * \brief Stat the path, return its metadata. * diff --git a/bindings/c/src/lib.rs b/bindings/c/src/lib.rs index ac125b0d4244..8ddd6e34c84e 100644 --- a/bindings/c/src/lib.rs +++ b/bindings/c/src/lib.rs @@ -46,6 +46,7 @@ pub use operator::opendal_operator; mod operator_info; mod result; +pub use result::opendal_result_exists; pub use result::opendal_result_is_exist; pub use result::opendal_result_list; pub use result::opendal_result_lister_next; diff --git a/bindings/c/src/operator.rs b/bindings/c/src/operator.rs index ba03f9c2ae92..3aa8b2e2a101 100644 --- a/bindings/c/src/operator.rs +++ b/bindings/c/src/operator.rs @@ -519,6 +519,7 @@ pub unsafe extern "C" fn opendal_operator_delete( /// /// * If the `path` points to NULL, this function panics, i.e. exits with information #[no_mangle] +#[deprecated(note = "Use opendal_operator_exists() instead.")] pub unsafe extern "C" fn opendal_operator_is_exist( op: &opendal_operator, path: *const c_char, @@ -527,7 +528,7 @@ pub unsafe extern "C" fn opendal_operator_is_exist( let path = std::ffi::CStr::from_ptr(path) .to_str() .expect("malformed path"); - match op.deref().is_exist(path) { + match op.deref().exists(path) { Ok(e) => opendal_result_is_exist { is_exist: e, error: std::ptr::null_mut(), @@ -539,6 +540,64 @@ pub unsafe extern "C" fn opendal_operator_is_exist( } } +/// \brief Check whether the path exists. +/// +/// If the operation succeeds, no matter the path exists or not, +/// the error should be a nullptr. Otherwise, the field `exists` +/// is filled with false, and the error is set +/// +/// @param op The opendal_operator created previously +/// @param path The path you want to check existence +/// @see opendal_operator +/// @see opendal_result_exists +/// @see opendal_error +/// @return Returns opendal_result_exists, the `exists` field contains whether the path exists. +/// However, it the operation fails, the `exists` will contain false and the error will be set. +/// +/// # Example +/// +/// ```C +/// // .. you previously wrote some data to path "/mytest/obj" +/// opendal_result_exists e = opendal_operator_exists(op, "/mytest/obj"); +/// assert(e.error == NULL); +/// assert(e.exists); +/// +/// // but you previously did **not** write any data to path "/yourtest/obj" +/// opendal_result_exists e = opendal_operator_exists(op, "/yourtest/obj"); +/// assert(e.error == NULL); +/// assert(!e.exists); +/// ``` +/// +/// # Safety +/// +/// It is **safe** under the cases below +/// * The memory pointed to by `path` must contain a valid nul terminator at the end of +/// the string. +/// +/// # Panic +/// +/// * If the `path` points to NULL, this function panics, i.e. exits with information +#[no_mangle] +pub unsafe extern "C" fn opendal_operator_exists( + op: &opendal_operator, + path: *const c_char, +) -> opendal_result_exists { + assert!(!path.is_null()); + let path = std::ffi::CStr::from_ptr(path) + .to_str() + .expect("malformed path"); + match op.deref().exists(path) { + Ok(e) => opendal_result_exists { + exists: e, + error: std::ptr::null_mut(), + }, + Err(e) => opendal_result_exists { + exists: false, + error: opendal_error::new(e), + }, + } +} + /// \brief Stat the path, return its metadata. /// /// Error is NULL if successful, otherwise it contains the error code and error message. diff --git a/bindings/c/src/result.rs b/bindings/c/src/result.rs index e9aede5d47fb..50a2b2fa5e36 100644 --- a/bindings/c/src/result.rs +++ b/bindings/c/src/result.rs @@ -70,6 +70,22 @@ pub struct opendal_result_is_exist { pub error: *mut opendal_error, } +/// \brief The result type returned by opendal_operator_exists(). +/// +/// The result type for opendal_operator_exists(), the field `exists` +/// contains whether the path exists, and the field `error` contains the +/// corresponding error. If successful, the `error` field is null. +/// +/// \note If the opendal_operator_exists() fails, the `exists` field +/// will be set to false. +#[repr(C)] +pub struct opendal_result_exists { + /// Whether the path exists + pub exists: bool, + /// The error, if ok, it is null + pub error: *mut opendal_error, +} + /// \brief The result type returned by opendal_operator_stat(). /// /// The result type for opendal_operator_stat(), the field `meta` contains the metadata diff --git a/bindings/c/tests/bdd.cpp b/bindings/c/tests/bdd.cpp index 16bea5f10e00..be218cf6b3fa 100644 --- a/bindings/c/tests/bdd.cpp +++ b/bindings/c/tests/bdd.cpp @@ -65,9 +65,9 @@ TEST_F(OpendalBddTest, FeatureTest) EXPECT_EQ(error, nullptr); // The blocking file "test" should exist - opendal_result_is_exist e = opendal_operator_is_exist(this->p, this->path.c_str()); + opendal_result_exists e = opendal_operator_exists(this->p, this->path.c_str()); EXPECT_EQ(e.error, nullptr); - EXPECT_TRUE(e.is_exist); + EXPECT_TRUE(e.exists); // The blocking file "test" entry mode must be file opendal_result_stat s = opendal_operator_stat(this->p, this->path.c_str()); @@ -93,9 +93,9 @@ TEST_F(OpendalBddTest, FeatureTest) // The blocking file should be deleted error = opendal_operator_delete(this->p, this->path.c_str()); EXPECT_EQ(error, nullptr); - e = opendal_operator_is_exist(this->p, this->path.c_str()); + e = opendal_operator_exists(this->p, this->path.c_str()); EXPECT_EQ(e.error, nullptr); - EXPECT_FALSE(e.is_exist); + EXPECT_FALSE(e.exists); opendal_result_operator_writer writer = opendal_operator_writer(this->p, this->path.c_str()); EXPECT_EQ(writer.error, nullptr);