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