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}