1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
#[allow(unused_imports)]
use paste::paste;
/// `ergo-lib` uses a number of collection types that are simple wrappers around `Vec`. We have a
/// generic type for such a collection in `ergo-lib-c-core::collections::Collection`. A limitation
/// of `cbindgen` is that it cannot process generic functions. This macro generates a C-compatible
/// interface for such a collection for any desired type T.
///
/// As an example the call `make_collection(BlockHeaders, BlockHeader);` generates:
///
///```
///pub type BlockHeadersPtr = CollectionPtr<BlockHeader>;
///pub type ConstBlockHeadersPtr = ConstCollectionPtr<BlockHeader>;
///
///#[no_mangle]
///pub unsafe extern "C" fn ergo_lib_block_headers_new(collection_ptr_out: *mut BlockHeadersPtr) {
/// #[allow(clippy::unwrap_used)]
/// collection_new(collection_ptr_out).unwrap();
///}
///
///#[no_mangle]
///pub unsafe extern "C" fn ergo_lib_block_headers_delete(collection_ptr_out: BlockHeadersPtr) {
/// collection_delete(collection_ptr_out)
///}
///
///#[no_mangle]
///pub unsafe extern "C" fn ergo_lib_block_headers_len(
/// collection_ptr: ConstBlockHeadersPtr,
///) -> usize {
/// #[allow(clippy::unwrap_used)]
/// collection_len(collection_ptr).unwrap()
///}
///
///#[no_mangle]
///pub unsafe extern "C" fn ergo_lib_block_headers_get(
/// collection_ptr: ConstBlockHeadersPtr,
/// index: usize,
/// element_ptr_out: *mut BlockHeaderPtr,
///) -> ReturnOption {
/// match collection_get(collection_ptr, index, element_ptr_out) {
/// Ok(is_some) => crate::ReturnOption {
/// is_some,
/// error: std::ptr::null_mut(),
/// },
/// Err(e) => crate::ReturnOption {
/// is_some: false, // Just a dummy value
/// error: Error::c_api_from(Err(e)),
/// },
/// }
///}
///
///#[no_mangle]
///pub unsafe extern "C" fn ergo_lib_block_headers_add(
/// element_ptr: ConstBlockHeaderPtr,
/// collection_ptr_out: BlockHeadersPtr,
///) {
/// #[allow(clippy::unwrap_used)]
/// collection_add(collection_ptr_out, element_ptr).unwrap();
///}
///```
#[macro_export]
macro_rules! make_collection {
($collection_type_name:ident, $item_type_name:ident) => {
paste! {
pub type [<$collection_type_name Ptr>] = ergo_lib_c_core::collections::CollectionPtr<$item_type_name>;
pub type [<Const $collection_type_name Ptr>] = ergo_lib_c_core::collections::ConstCollectionPtr<$item_type_name>;
/// Create a new empty collection
#[no_mangle]
pub unsafe extern "C" fn [<ergo_lib_ $collection_type_name:snake _new>](
collection_ptr_out: *mut [<$collection_type_name Ptr>],
) {
#[allow(clippy::unwrap_used)]
ergo_lib_c_core::collections::collection_new(collection_ptr_out).unwrap();
}
/// Delete an existing collection
#[no_mangle]
pub unsafe extern "C" fn [<ergo_lib_ $collection_type_name:snake _delete>](ptr_out: [<$collection_type_name Ptr>]) {
ergo_lib_c_core::collections::collection_delete(ptr_out)
}
/// Returns length of an existing collection
#[no_mangle]
pub unsafe extern "C" fn [<ergo_lib_ $collection_type_name:snake _len>](
collection_ptr: [<Const $collection_type_name Ptr>],
) -> usize {
#[allow(clippy::unwrap_used)]
ergo_lib_c_core::collections::collection_len(collection_ptr).unwrap()
}
/// Returns element at position `index` of an existing collection
#[no_mangle]
pub unsafe extern "C" fn [<ergo_lib_ $collection_type_name:snake _get>](
collection_ptr: [<Const $collection_type_name Ptr>],
index: usize,
element_ptr_out: *mut [<$item_type_name Ptr>],
) -> $crate::ReturnOption {
match ergo_lib_c_core::collections::collection_get(collection_ptr, index, element_ptr_out) {
Ok(is_some) => $crate::ReturnOption {
is_some,
error: std::ptr::null_mut(),
},
Err(e) => $crate::ReturnOption {
is_some: false, // Just a dummy value
error: Error::c_api_from(Err(e)),
},
}
}
#[no_mangle]
/// Add an element to collection
pub unsafe extern "C" fn [<ergo_lib_ $collection_type_name:snake _add>](
element_ptr: [<Const $item_type_name Ptr>],
collection_ptr_out: [<$collection_type_name Ptr>],
) {
#[allow(clippy::unwrap_used)]
ergo_lib_c_core::collections::collection_add(collection_ptr_out, element_ptr).unwrap();
}
}
};
}
/// Generates an equality function for FFI
#[macro_export]
macro_rules! make_ffi_eq {
($type_name:ident) => {
paste! {
#[no_mangle]
pub unsafe extern "C" fn [<ergo_lib_ $type_name:snake _eq>](
[< $type_name:snake _ptr_0>]: [< Const $type_name Ptr>],
[< $type_name:snake _ptr_1>]: [< Const $type_name Ptr>],
) -> bool {
ergo_lib_c_core::util::deref_eq([< $type_name:snake _ptr_0>], [< $type_name:snake _ptr_1>])
}
}
};
}