diff --git a/CHANGELOG.md b/CHANGELOG.md index d62caff..21fe261 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,20 @@ Also check the changes in springql-core: ## [Unreleased] +## [v0.14.0] - 2022-06-24 + +### Changed + +- `SpringRow` into `SpringSinkRow` ([#50](https://github.com/SpringQL/SpringQL-client-c/pull/50)) +- `spring_row_close` -> `spring_sink_row_close` ([#50](https://github.com/SpringQL/SpringQL-client-c/pull/50)) + +### Added + +- Following new APIs: ([#50](https://github.com/SpringQL/SpringQL-client-c/pull/50)) + - `SpringSourceRow` + - `spring_source_row_from_json` + - `spring_source_row_close` + ## [v0.13.0+4] ### Fixed diff --git a/Cargo.toml b/Cargo.toml index f6be196..f0d1d50 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "springql-client-c" -version = "0.13.0+4" +version = "0.14.0" authors = ["Sho Nakatani "] license = "MIT OR Apache-2.0" @@ -15,6 +15,6 @@ name = "springql_client" cbindgen = "0.24" [dependencies] -springql-core = "0.13.0" +springql = "0.14.0" log = "0.4" diff --git a/c_example/doc_app1/doc_app1.c b/c_example/doc_app1/doc_app1.c index af02e5a..577b3ba 100644 --- a/c_example/doc_app1/doc_app1.c +++ b/c_example/doc_app1/doc_app1.c @@ -91,7 +91,7 @@ int main() fprintf(stderr, "waiting JSON records in tcp/54300...\n"); - SpringRow *row; + SpringSinkRow *row; while (1) { row = spring_pop(pipeline, "q"); @@ -108,7 +108,7 @@ int main() assert_ok(ret); fprintf(stderr, "%s\t%f\n", ts, temperature_fahrenheit); - spring_row_close(row); + spring_sink_row_close(row); } ret = spring_close(pipeline); diff --git a/c_example/doc_app2/doc_app2.c b/c_example/doc_app2/doc_app2.c index 6e9a594..50e32b5 100644 --- a/c_example/doc_app2/doc_app2.c +++ b/c_example/doc_app2/doc_app2.c @@ -137,7 +137,7 @@ int main() fprintf(stderr, "waiting JSON records in tcp/54300...\n"); - SpringRow *row; + SpringSinkRow *row; bool is_err = false; while (1) { @@ -159,7 +159,7 @@ int main() assert_ok(ret); fprintf(stderr, "[q_avg_all] %s\t%f\n", ts, avg_amount); - spring_row_close(row); + spring_sink_row_close(row); } else { @@ -182,7 +182,7 @@ int main() assert_ok(ret); fprintf(stderr, "[q_avg_by_symbol] %s\t%s\t%f\n", ts, symbol, avg_amount); - spring_row_close(row); + spring_sink_row_close(row); } else { diff --git a/c_example/trade_projection/trade_projection.c b/c_example/trade_projection/trade_projection.c index 8e4b900..3fe57fb 100644 --- a/c_example/trade_projection/trade_projection.c +++ b/c_example/trade_projection/trade_projection.c @@ -91,7 +91,7 @@ void pop_print(const SpringPipeline *pipeline) { SpringErrno ret; - SpringRow *row = spring_pop(pipeline, "q_sink_trade"); + SpringSinkRow *row = spring_pop(pipeline, "q_sink_trade"); assert_not_null(row); int r = spring_column_text(row, 0, (char *)ts, TS_LEN); @@ -103,7 +103,7 @@ void pop_print(const SpringPipeline *pipeline) printf("[row#%d] ts=%s amount=%d\n", i, ts, amount); - spring_row_close(row); + spring_sink_row_close(row); } } diff --git a/springql.h b/springql.h index 5276818..9ee865a 100644 --- a/springql.h +++ b/springql.h @@ -50,9 +50,14 @@ typedef void *SpringConfig; typedef void *SpringPipeline; /** - * Row object from an in memory queue. + * Row object to pop from an in memory queue. */ -typedef void *SpringRow; +typedef void *SpringSinkRow; + +/** + * Row object to push into an in memory queue. + */ +typedef void *SpringSourceRow; /** * Returns default configuration. @@ -146,7 +151,7 @@ enum SpringErrno spring_command(const SpringPipeline *pipeline, const char *sql) * * - `Unavailable`: queue named `queue` does not exist. */ -SpringRow *spring_pop(const SpringPipeline *pipeline, const char *queue); +SpringSinkRow *spring_pop(const SpringPipeline *pipeline, const char *queue); /** * Pop a row from an in memory queue. This is a non-blocking function. @@ -160,19 +165,55 @@ SpringRow *spring_pop(const SpringPipeline *pipeline, const char *queue); * * - `Unavailable`: queue named `queue` does not exist. */ -SpringRow *spring_pop_non_blocking(const SpringPipeline *pipeline, - const char *queue, - bool *is_err); +SpringSinkRow *spring_pop_non_blocking(const SpringPipeline *pipeline, + const char *queue, + bool *is_err); + +/** + * Push a row into an in memory queue. This is a non-blocking function. + * + * # Returns + * + * - `Ok`: on success. + * - `Unavailable`: queue named `queue` does not exist. + */ +enum SpringErrno spring_push(const SpringPipeline *pipeline, + const char *queue, + const SpringSourceRow *row); + +/** + * Create a source row from JSON string + * + * # Returns + * + * - non-NULL: Successfully created a row. + * - NULL: Error occurred. + * + * # Errors + * + * - `InvalidFormat`: JSON string is invalid. + */ +SpringSourceRow *spring_source_row_from_json(const char *json); + +/** + * Frees heap occupied by a `SpringSourceRow`. + * + * # Returns + * + * - `Ok`: on success. + * - `CNull`: `pipeline` is a NULL pointer. + */ +enum SpringErrno spring_source_row_close(SpringSourceRow *row); /** - * Frees heap occupied by a `SpringRow`. + * Frees heap occupied by a `SpringSinkRow`. * * # Returns * * - `Ok`: on success. * - `CNull`: `pipeline` is a NULL pointer. */ -enum SpringErrno spring_row_close(SpringRow *row); +enum SpringErrno spring_sink_row_close(SpringSinkRow *row); /** * Get a 2-byte integer column. @@ -191,7 +232,7 @@ enum SpringErrno spring_row_close(SpringRow *row); * - `i_col` is out of range. * - `CNull`: Column value is NULL. */ -enum SpringErrno spring_column_short(const SpringRow *row, uint16_t i_col, short *out); +enum SpringErrno spring_column_short(const SpringSinkRow *row, uint16_t i_col, short *out); /** * Get a 4-byte integer column. @@ -210,7 +251,7 @@ enum SpringErrno spring_column_short(const SpringRow *row, uint16_t i_col, short * - `i_col` is out of range. * - `CNull`: Column value is NULL. */ -enum SpringErrno spring_column_int(const SpringRow *row, uint16_t i_col, int *out); +enum SpringErrno spring_column_int(const SpringSinkRow *row, uint16_t i_col, int *out); /** * Get an 8-byte integer column. @@ -229,7 +270,7 @@ enum SpringErrno spring_column_int(const SpringRow *row, uint16_t i_col, int *ou * - `i_col` is out of range. * - `CNull`: Column value is NULL. */ -enum SpringErrno spring_column_long(const SpringRow *row, uint16_t i_col, long *out); +enum SpringErrno spring_column_long(const SpringSinkRow *row, uint16_t i_col, long *out); /** * Get a 4-byte unsigned integer column. @@ -248,7 +289,7 @@ enum SpringErrno spring_column_long(const SpringRow *row, uint16_t i_col, long * * - `i_col` is out of range. * - `CNull`: Column value is NULL. */ -enum SpringErrno spring_column_unsigned_int(const SpringRow *row, +enum SpringErrno spring_column_unsigned_int(const SpringSinkRow *row, uint16_t i_col, unsigned int *out); @@ -270,7 +311,7 @@ enum SpringErrno spring_column_unsigned_int(const SpringRow *row, * - `i_col` is out of range. * - `CNull`: Column value is NULL. */ -int spring_column_text(const SpringRow *row, uint16_t i_col, char *out, int out_len); +int spring_column_text(const SpringSinkRow *row, uint16_t i_col, char *out, int out_len); /** * Get a BLOB column. @@ -290,7 +331,7 @@ int spring_column_text(const SpringRow *row, uint16_t i_col, char *out, int out_ * - `i_col` is out of range. * - `CNull`: Column value is NULL. */ -int spring_column_blob(const SpringRow *row, uint16_t i_col, void *out, int out_len); +int spring_column_blob(const SpringSinkRow *row, uint16_t i_col, void *out, int out_len); /** * Get a bool column. @@ -309,7 +350,7 @@ int spring_column_blob(const SpringRow *row, uint16_t i_col, void *out, int out_ * - `i_col` is out of range. * - `CNull`: Column value is NULL. */ -enum SpringErrno spring_column_bool(const SpringRow *row, uint16_t i_col, bool *out); +enum SpringErrno spring_column_bool(const SpringSinkRow *row, uint16_t i_col, bool *out); /** * Get a 4-byte floating point column. @@ -328,7 +369,7 @@ enum SpringErrno spring_column_bool(const SpringRow *row, uint16_t i_col, bool * * - `i_col` is out of range. * - `CNull`: Column value is NULL. */ -enum SpringErrno spring_column_float(const SpringRow *row, uint16_t i_col, float *out); +enum SpringErrno spring_column_float(const SpringSinkRow *row, uint16_t i_col, float *out); /** * Write the most recent error number into `errno` and message into a caller-provided buffer as a UTF-8 diff --git a/src/lib.rs b/src/lib.rs index aeb5c8e..ff9e4ff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,7 +9,8 @@ mod spring_config; pub mod spring_errno; pub mod spring_last_err; mod spring_pipeline; -mod spring_row; +mod spring_sink_row; +mod spring_source_row; use std::{ ffi::{c_void, CStr}, @@ -24,9 +25,10 @@ use crate::{ spring_errno::SpringErrno, spring_last_err::{update_last_error, LastError}, spring_pipeline::SpringPipeline, - spring_row::SpringRow, + spring_sink_row::SpringSinkRow, + spring_source_row::SpringSourceRow, }; -use ::springql_core::api::{error::SpringError, SpringPipeline as Pipeline}; +use ::springql::{error::SpringError, SpringPipeline as Pipeline}; /// Returns default configuration. /// @@ -34,7 +36,7 @@ use ::springql_core::api::{error::SpringError, SpringPipeline as Pipeline}; /// If you would like to change the default configuration, use `spring_config_toml()` instead. #[no_mangle] pub extern "C" fn spring_config_default() -> *mut SpringConfig { - let config = ::springql_core::api::SpringConfig::default(); + let config = ::springql::SpringConfig::default(); SpringConfig::new(config).into_ptr() } @@ -60,7 +62,7 @@ pub unsafe extern "C" fn spring_config_toml( let s = CStr::from_ptr(overwrite_config_toml); let s = s.to_str().expect("failed to parse TOML string into UTF-8"); - let config = springql_core::api::SpringConfig::new(s).expect("failed to parse TOML config"); + let config = springql::SpringConfig::new(s).expect("failed to parse TOML config"); SpringConfig::new(config).into_ptr() } @@ -163,13 +165,13 @@ pub unsafe extern "C" fn spring_command( pub unsafe extern "C" fn spring_pop( pipeline: *const SpringPipeline, queue: *const c_char, -) -> *mut SpringRow { +) -> *mut SpringSinkRow { let pipeline = (*pipeline).as_pipeline(); let queue = CStr::from_ptr(queue).to_string_lossy().into_owned(); let result = with_catch(|| pipeline.pop(&queue)); match result { Ok(row) => { - let row = SpringRow::new(row); + let row = SpringSinkRow::new(row); row.into_ptr() } Err(_) => ptr::null_mut(), @@ -191,13 +193,13 @@ pub unsafe extern "C" fn spring_pop_non_blocking( pipeline: *const SpringPipeline, queue: *const c_char, is_err: *mut bool, -) -> *mut SpringRow { +) -> *mut SpringSinkRow { let pipeline = (*pipeline).as_pipeline(); let queue = CStr::from_ptr(queue).to_string_lossy().into_owned(); let result = with_catch(|| pipeline.pop_non_blocking(&queue)); match result { Ok(Some(row)) => { - let ptr = SpringRow::new(row); + let ptr = SpringSinkRow::new(row); *is_err = false; ptr.into_ptr() } @@ -212,18 +214,76 @@ pub unsafe extern "C" fn spring_pop_non_blocking( } } -/// Frees heap occupied by a `SpringRow`. +/// Push a row into an in memory queue. This is a non-blocking function. +/// +/// # Returns +/// +/// - `Ok`: on success. +/// - `Unavailable`: queue named `queue` does not exist. +#[no_mangle] +pub unsafe extern "C" fn spring_push( + pipeline: *const SpringPipeline, + queue: *const c_char, + row: *const SpringSourceRow, +) -> SpringErrno { + let pipeline = (*pipeline).as_pipeline(); + let queue = CStr::from_ptr(queue).to_string_lossy().into_owned(); + let source_row = (*row).to_row(); + let result = with_catch(|| pipeline.push(&queue, source_row)); + match result { + Ok(()) => SpringErrno::Ok, + Err(e) => e, + } +} + +/// Create a source row from JSON string +/// +/// # Returns +/// +/// - non-NULL: Successfully created a row. +/// - NULL: Error occurred. +/// +/// # Errors +/// +/// - `InvalidFormat`: JSON string is invalid. +#[no_mangle] +pub unsafe extern "C" fn spring_source_row_from_json(json: *const c_char) -> *mut SpringSourceRow { + let json = CStr::from_ptr(json).to_string_lossy().into_owned(); + let res_source_row = with_catch(|| ::springql::SpringSourceRow::from_json(&json)); + match res_source_row { + Ok(source_row) => SpringSourceRow::new(source_row).into_ptr(), + Err(_) => ptr::null_mut(), + } +} + +/// Frees heap occupied by a `SpringSourceRow`. +/// +/// # Returns +/// +/// - `Ok`: on success. +/// - `CNull`: `pipeline` is a NULL pointer. +#[no_mangle] +pub extern "C" fn spring_source_row_close(row: *mut SpringSourceRow) -> SpringErrno { + if row.is_null() { + SpringErrno::CNull + } else { + SpringSourceRow::drop(row); + SpringErrno::Ok + } +} + +/// Frees heap occupied by a `SpringSinkRow`. /// /// # Returns /// /// - `Ok`: on success. /// - `CNull`: `pipeline` is a NULL pointer. #[no_mangle] -pub extern "C" fn spring_row_close(row: *mut SpringRow) -> SpringErrno { +pub extern "C" fn spring_sink_row_close(row: *mut SpringSinkRow) -> SpringErrno { if row.is_null() { SpringErrno::CNull } else { - SpringRow::drop(row); + SpringSinkRow::drop(row); SpringErrno::Ok } } @@ -245,7 +305,7 @@ pub extern "C" fn spring_row_close(row: *mut SpringRow) -> SpringErrno { /// - `CNull`: Column value is NULL. #[no_mangle] pub unsafe extern "C" fn spring_column_short( - row: *const SpringRow, + row: *const SpringSinkRow, i_col: u16, out: *mut c_short, ) -> SpringErrno { @@ -278,7 +338,7 @@ pub unsafe extern "C" fn spring_column_short( /// - `CNull`: Column value is NULL. #[no_mangle] pub unsafe extern "C" fn spring_column_int( - row: *const SpringRow, + row: *const SpringSinkRow, i_col: u16, out: *mut c_int, ) -> SpringErrno { @@ -311,7 +371,7 @@ pub unsafe extern "C" fn spring_column_int( /// - `CNull`: Column value is NULL. #[no_mangle] pub unsafe extern "C" fn spring_column_long( - row: *const SpringRow, + row: *const SpringSinkRow, i_col: u16, out: *mut c_long, ) -> SpringErrno { @@ -344,7 +404,7 @@ pub unsafe extern "C" fn spring_column_long( /// - `CNull`: Column value is NULL. #[no_mangle] pub unsafe extern "C" fn spring_column_unsigned_int( - row: *const SpringRow, + row: *const SpringSinkRow, i_col: u16, out: *mut c_uint, ) -> SpringErrno { @@ -378,7 +438,7 @@ pub unsafe extern "C" fn spring_column_unsigned_int( /// - `CNull`: Column value is NULL. #[no_mangle] pub unsafe extern "C" fn spring_column_text( - row: *const SpringRow, + row: *const SpringSinkRow, i_col: u16, out: *mut c_char, out_len: c_int, @@ -414,7 +474,7 @@ pub unsafe extern "C" fn spring_column_text( /// - `CNull`: Column value is NULL. #[no_mangle] pub unsafe extern "C" fn spring_column_blob( - row: *const SpringRow, + row: *const SpringSinkRow, i_col: u16, out: *mut c_void, out_len: c_int, @@ -449,7 +509,7 @@ pub unsafe extern "C" fn spring_column_blob( /// - `CNull`: Column value is NULL. #[no_mangle] pub unsafe extern "C" fn spring_column_bool( - row: *const SpringRow, + row: *const SpringSinkRow, i_col: u16, out: *mut bool, ) -> SpringErrno { @@ -482,7 +542,7 @@ pub unsafe extern "C" fn spring_column_bool( /// - `CNull`: Column value is NULL. #[no_mangle] pub unsafe extern "C" fn spring_column_float( - row: *const SpringRow, + row: *const SpringSinkRow, i_col: u16, out: *mut c_float, ) -> SpringErrno { diff --git a/src/spring_config.rs b/src/spring_config.rs index 6b57fe8..abd5337 100644 --- a/src/spring_config.rs +++ b/src/spring_config.rs @@ -1,5 +1,5 @@ // This file is part of https://github.com/SpringQL/SpringQL-client-c which is licensed under MIT OR Apache-2.0. See file LICENSE-MIT or LICENSE-APACHE for full license details. -use ::springql_core::api::SpringConfig as RawSpringConfig; +use ::springql::SpringConfig as RawSpringConfig; use std::{ffi::c_void, mem}; /// Configuration. #[non_exhaustive] diff --git a/src/spring_errno.rs b/src/spring_errno.rs index 5f511bf..6bc0a6f 100644 --- a/src/spring_errno.rs +++ b/src/spring_errno.rs @@ -1,6 +1,6 @@ // This file is part of https://github.com/SpringQL/SpringQL-client-c which is licensed under MIT OR Apache-2.0. See file LICENSE-MIT or LICENSE-APACHE for full license details. -use ::springql_core::api::error::SpringError; +use ::springql::error::SpringError; use crate::spring_last_err::LastError; diff --git a/src/spring_last_err.rs b/src/spring_last_err.rs index 143e01f..9784df6 100644 --- a/src/spring_last_err.rs +++ b/src/spring_last_err.rs @@ -9,7 +9,7 @@ use std::{ }; use ::log::{info, warn}; -use ::springql_core::api::error::SpringError; +use ::springql::error::SpringError; use crate::{c_mem::strcpy, spring_errno::SpringErrno}; diff --git a/src/spring_pipeline.rs b/src/spring_pipeline.rs index ef31247..b5a34f5 100644 --- a/src/spring_pipeline.rs +++ b/src/spring_pipeline.rs @@ -1,5 +1,5 @@ // This file is part of https://github.com/SpringQL/SpringQL-client-c which is licensed under MIT OR Apache-2.0. See file LICENSE-MIT or LICENSE-APACHE for full license details. -use ::springql_core::api::SpringPipeline as Pipeline; +use ::springql::SpringPipeline as Pipeline; use std::{ffi::c_void, mem}; /// Pipeline (dataflow definition) in SpringQL. diff --git a/src/spring_row.rs b/src/spring_sink_row.rs similarity index 51% rename from src/spring_row.rs rename to src/spring_sink_row.rs index 8706f49..1415254 100644 --- a/src/spring_row.rs +++ b/src/spring_sink_row.rs @@ -1,30 +1,31 @@ // This file is part of https://github.com/SpringQL/SpringQL-client-c which is licensed under MIT OR Apache-2.0. See file LICENSE-MIT or LICENSE-APACHE for full license details. -use ::springql_core::api::SpringRow as Row; +use ::springql::SpringSinkRow as SinkRow; use std::{ffi::c_void, mem}; -/// Row object from an in memory queue. + +/// Row object to pop from an in memory queue. #[non_exhaustive] #[repr(transparent)] -pub struct SpringRow(*mut c_void); +pub struct SpringSinkRow(*mut c_void); -impl SpringRow { - pub fn new(pipe: Row) -> Self { - SpringRow(unsafe { mem::transmute(Box::new(pipe)) }) +impl SpringSinkRow { + pub fn new(sink_row: SinkRow) -> Self { + SpringSinkRow(unsafe { mem::transmute(Box::new(sink_row)) }) } - pub fn as_row(&self) -> &Row { - unsafe { &*(self.0 as *const Row) } + pub fn as_row(&self) -> &SinkRow { + unsafe { &*(self.0 as *const SinkRow) } } - pub fn drop(ptr: *mut SpringRow) { + pub fn drop(ptr: *mut SpringSinkRow) { let outer = unsafe { Box::from_raw(ptr) }; let inner = unsafe { Box::from_raw(outer.0) }; drop(inner); drop(outer); } - pub fn into_ptr(self) -> *mut SpringRow { + pub fn into_ptr(self) -> *mut SpringSinkRow { Box::into_raw(Box::new(self)) } } diff --git a/src/spring_source_row.rs b/src/spring_source_row.rs new file mode 100644 index 0000000..f792a7c --- /dev/null +++ b/src/spring_source_row.rs @@ -0,0 +1,31 @@ +// This file is part of https://github.com/SpringQL/SpringQL-client-c which is licensed under MIT OR Apache-2.0. See file LICENSE-MIT or LICENSE-APACHE for full license details. + +use ::springql::SpringSourceRow as SourceRow; + +use std::{ffi::c_void, mem}; + +/// Row object to push into an in memory queue. +#[non_exhaustive] +#[repr(transparent)] +pub struct SpringSourceRow(*mut c_void); + +impl SpringSourceRow { + pub fn new(source_row: SourceRow) -> Self { + SpringSourceRow(unsafe { mem::transmute(Box::new(source_row)) }) + } + + pub fn to_row(&self) -> SourceRow { + unsafe { &*(self.0 as *const SourceRow) }.clone() + } + + pub fn drop(ptr: *mut SpringSourceRow) { + let outer = unsafe { Box::from_raw(ptr) }; + let inner = unsafe { Box::from_raw(outer.0) }; + drop(inner); + drop(outer); + } + + pub fn into_ptr(self) -> *mut SpringSourceRow { + Box::into_raw(Box::new(self)) + } +}