1+ // Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/ 
2+ // SPDX-License-Identifier: Apache-2.0 
3+ 
4+ use  super :: { Metadata ,  SigInfo } ; 
5+ use  :: function_name:: named; 
6+ use  datadog_crashtracker:: { CrashPingBuilder ,  CrashPing } ; 
7+ use  ddcommon:: Endpoint ; 
8+ use  ddcommon_ffi:: { 
9+     slice:: AsBytes ,  wrap_with_ffi_result,  wrap_with_void_ffi_result,  CharSlice ,  Error ,  Handle , 
10+     ToInner ,  VoidResult , 
11+ } ; 
12+ 
13+ //////////////////////////////////////////////////////////////////////////////////////////////////// 
14+ //                                              FFI API                                           // 
15+ //////////////////////////////////////////////////////////////////////////////////////////////////// 
16+ 
17+ #[ allow( dead_code) ]  
18+ #[ repr( C ) ]  
19+ pub  enum  PingInfoBuilderNewResult  { 
20+     Ok ( Handle < CrashPingBuilder > ) , 
21+     Err ( Error ) , 
22+ } 
23+ 
24+ /// Create a new CrashPingBuilder, and returns an opaque reference to it. 
25+ /// # Safety 
26+ /// No safety issues. 
27+ #[ no_mangle]  
28+ #[ must_use]  
29+ pub  unsafe  extern  "C"  fn  ddog_crasht_PingInfoBuilder_new ( )  -> PingInfoBuilderNewResult  { 
30+     PingInfoBuilderNewResult :: Ok ( CrashPingBuilder :: new ( ) . into ( ) ) 
31+ } 
32+ 
33+ /// # Safety 
34+ /// The `builder` can be null, but if non-null it must point to a PingInfoBuilder 
35+ /// made by this module, which has not previously been dropped. 
36+ #[ no_mangle]  
37+ pub  unsafe  extern  "C"  fn  ddog_crasht_PingInfoBuilder_drop ( builder :  * mut  Handle < CrashPingBuilder > )  { 
38+     // Technically, this function has been designed so if it's double-dropped 
39+     // then it's okay, but it's not something that should be relied on. 
40+     if  !builder. is_null ( )  { 
41+         drop ( ( * builder) . take ( ) ) 
42+     } 
43+ } 
44+ 
45+ #[ allow( dead_code) ]  
46+ #[ repr( C ) ]  
47+ pub  enum  PingInfoNewResult  { 
48+     Ok ( Handle < CrashPing > ) , 
49+     Err ( Error ) , 
50+ } 
51+ 
52+ /// # Safety 
53+ /// The `builder` can be null, but if non-null it must point to a PingInfoBuilder made by this module, 
54+ /// which has not previously been dropped. 
55+ #[ no_mangle]  
56+ #[ must_use]  
57+ pub  unsafe  extern  "C"  fn  ddog_crasht_PingInfoBuilder_build ( 
58+     builder :  * mut  Handle < CrashPingBuilder > , 
59+ )  -> PingInfoNewResult  { 
60+     match  ddog_crasht_ping_info_builder_build_impl ( builder)  { 
61+         Ok ( ping_info)  => PingInfoNewResult :: Ok ( ping_info) , 
62+         Err ( err)  => PingInfoNewResult :: Err ( err. into ( ) ) , 
63+     } 
64+ } 
65+ 
66+ #[ named]  
67+ unsafe  fn  ddog_crasht_ping_info_builder_build_impl ( 
68+     mut  builder :  * mut  Handle < CrashPingBuilder > , 
69+ )  -> anyhow:: Result < Handle < CrashPing > >  { 
70+     wrap_with_ffi_result ! ( {  anyhow:: Ok ( builder. take( ) ?. build( ) ?. into( ) )  } ) 
71+ } 
72+ 
73+ /// # Safety 
74+ /// The `builder` can be null, but if non-null it must point to a PingInfoBuilder made by this module, 
75+ /// which has not previously been dropped. 
76+ /// The uuid CharSlice must be valid. 
77+ #[ no_mangle]  
78+ #[ must_use]  
79+ #[ named]  
80+ pub  unsafe  extern  "C"  fn  ddog_crasht_PingInfoBuilder_with_uuid ( 
81+     mut  builder :  * mut  Handle < CrashPingBuilder > , 
82+     uuid :  CharSlice , 
83+ )  -> VoidResult  { 
84+     wrap_with_void_ffi_result ! ( { 
85+         // Take the builder, apply the method, and put it back 
86+         let  old_builder = builder. take( ) ?; 
87+         let  new_builder = old_builder. with_crash_uuid( uuid. try_to_string( ) ?) ; 
88+         * builder = new_builder. into( ) ; 
89+     } ) 
90+ } 
91+ 
92+ /// # Safety 
93+ /// The `builder` can be null, but if non-null it must point to a PingInfoBuilder made by this module, 
94+ /// which has not previously been dropped. 
95+ /// The metadata must be valid. 
96+ #[ no_mangle]  
97+ #[ must_use]  
98+ #[ named]  
99+ pub  unsafe  extern  "C"  fn  ddog_crasht_PingInfoBuilder_with_metadata ( 
100+     mut  builder :  * mut  Handle < CrashPingBuilder > , 
101+     metadata :  Metadata , 
102+ )  -> VoidResult  { 
103+     wrap_with_void_ffi_result ! ( { 
104+         // Take the builder, apply the method, and put it back 
105+         let  old_builder = builder. take( ) ?; 
106+         let  new_builder = old_builder. with_metadata( metadata. try_into( ) ?) ; 
107+         * builder = new_builder. into( ) ; 
108+     } ) 
109+ } 
110+ 
111+ /// # Safety 
112+ /// The `builder` can be null, but if non-null it must point to a PingInfoBuilder made by this module, 
113+ /// which has not previously been dropped. 
114+ /// The sig_info must be valid. 
115+ #[ no_mangle]  
116+ #[ must_use]  
117+ #[ named]  
118+ pub  unsafe  extern  "C"  fn  ddog_crasht_PingInfoBuilder_with_sig_info ( 
119+     mut  builder :  * mut  Handle < CrashPingBuilder > , 
120+     sig_info :  SigInfo , 
121+ )  -> VoidResult  { 
122+     wrap_with_void_ffi_result ! ( { 
123+         // Take the builder, apply the method, and put it back 
124+         let  old_builder = builder. take( ) ?; 
125+         let  new_builder = old_builder. with_sig_info( sig_info. try_into( ) ?) ; 
126+         * builder = new_builder. into( ) ; 
127+     } ) 
128+ } 
129+ 
130+ /// # Safety 
131+ /// The `builder` can be null, but if non-null it must point to a PingInfoBuilder made by this module, 
132+ /// which has not previously been dropped. 
133+ #[ no_mangle]  
134+ #[ must_use]  
135+ #[ named]  
136+ pub  unsafe  extern  "C"  fn  ddog_crasht_PingInfoBuilder_with_os_info_this_machine ( 
137+     mut  builder :  * mut  Handle < CrashPingBuilder > , 
138+ )  -> VoidResult  { 
139+     wrap_with_void_ffi_result ! ( { 
140+         // Take the builder, apply the method, and put it back 
141+         let  old_builder = builder. take( ) ?; 
142+         let  new_builder = old_builder. with_os_info_this_machine( ) ; 
143+         * builder = new_builder. into( ) ; 
144+     } ) 
145+ } 
146+ 
147+ /// # Safety 
148+ /// The `builder` can be null, but if non-null it must point to a PingInfoBuilder made by this module, 
149+ /// which has not previously been dropped. 
150+ #[ no_mangle]  
151+ #[ must_use]  
152+ #[ named]  
153+ pub  unsafe  extern  "C"  fn  ddog_crasht_PingInfoBuilder_with_proc_info ( 
154+     mut  builder :  * mut  Handle < CrashPingBuilder > , 
155+ )  -> VoidResult  { 
156+     wrap_with_void_ffi_result ! ( { 
157+         // Take the builder, apply the method, and put it back 
158+         let  old_builder = builder. take( ) ?; 
159+         let  new_builder = old_builder. with_proc_info_this_process( ) ; 
160+         * builder = new_builder. into( ) ; 
161+     } ) 
162+ } 
163+ 
164+ /// # Safety 
165+ /// The `ping_info` can be null, but if non-null it must point to a PingInfo 
166+ /// made by this module, which has not previously been dropped. 
167+ #[ no_mangle]  
168+ pub  unsafe  extern  "C"  fn  ddog_crasht_PingInfo_drop ( ping_info :  * mut  Handle < CrashPing > )  { 
169+     // Technically, this function has been designed so if it's double-dropped 
170+     // then it's okay, but it's not something that should be relied on. 
171+     if  !ping_info. is_null ( )  { 
172+         drop ( ( * ping_info) . take ( ) ) 
173+     } 
174+ } 
175+ 
176+ /// # Safety 
177+ /// The `ping_info` can be null, but if non-null it must point to a PingInfo made by this module, 
178+ /// which has not previously been dropped. 
179+ /// The endpoint can be null (uses builder's endpoint) or must be valid. 
180+ #[ no_mangle]  
181+ #[ must_use]  
182+ #[ named]  
183+ pub  unsafe  extern  "C"  fn  ddog_crasht_PingInfo_upload_to_endpoint ( 
184+     mut  ping_info :  * mut  Handle < CrashPing > , 
185+     endpoint :  * const  Endpoint , 
186+ )  -> VoidResult  { 
187+     wrap_with_void_ffi_result ! ( { 
188+         // Create a runtime to block on the async upload 
189+         let  rt = tokio:: runtime:: Builder :: new_current_thread( ) 
190+             . enable_all( ) 
191+             . build( ) ?; 
192+ 
193+         // Take the ping_info and upload it 
194+         let  ping = ping_info. take( ) ?; 
195+ 
196+         // For now, we use the endpoint from the builder. In the future, we could 
197+         // extend CrashPing to support endpoint override if needed. 
198+         // The endpoint parameter is reserved for future use. 
199+         if  !endpoint. is_null( )  { 
200+             // TODO: Consider supporting endpoint override during upload 
201+             // For now, we ignore the endpoint parameter and use the builder's endpoint 
202+         } 
203+ 
204+         rt. block_on( ping. upload( ) ) ?; 
205+     } ) 
206+ } 
207+ 
208+ #[ cfg( test) ]  
209+ mod  tests { 
210+     use  super :: * ; 
211+     use  ddcommon_ffi:: CharSlice ; 
212+ 
213+     #[ test]  
214+     #[ cfg_attr( miri,  ignore) ]  
215+     fn  test_ping_info_builder_ffi_basic ( )  { 
216+         unsafe  { 
217+             // Create builder 
218+             let  builder_result = ddog_crasht_PingInfoBuilder_new ( ) ; 
219+             let  mut  builder = match  builder_result { 
220+                 PingInfoBuilderNewResult :: Ok ( b)  => b, 
221+                 PingInfoBuilderNewResult :: Err ( _)  => panic ! ( "Failed to create builder" ) , 
222+             } ; 
223+ 
224+             // Add UUID 
225+             let  uuid_slice = CharSlice :: from ( "test-uuid-ffi-123" ) ; 
226+             let  result = ddog_crasht_PingInfoBuilder_with_uuid ( & mut  builder,  uuid_slice) ; 
227+             match  result { 
228+                 ddcommon_ffi:: VoidResult :: Ok  => { } , 
229+                 ddcommon_ffi:: VoidResult :: Err ( _)  => panic ! ( "Failed to set UUID" ) , 
230+             } 
231+ 
232+             // Add metadata 
233+             let  tags = ddcommon_ffi:: Vec :: new ( ) ; 
234+ 
235+             let  metadata = Metadata  { 
236+                 library_name :  CharSlice :: from ( "test-library" ) , 
237+                 library_version :  CharSlice :: from ( "1.0.0" ) , 
238+                 family :  CharSlice :: from ( "test" ) , 
239+                 tags :  Some ( & tags) , 
240+             } ; 
241+ 
242+             let  result = ddog_crasht_PingInfoBuilder_with_metadata ( & mut  builder,  metadata) ; 
243+             match  result { 
244+                 ddcommon_ffi:: VoidResult :: Ok  => { } , 
245+                 ddcommon_ffi:: VoidResult :: Err ( _)  => panic ! ( "Failed to set metadata" ) , 
246+             } 
247+ 
248+             // Add sig_info 
249+             let  sig_info = SigInfo  { 
250+                 addr :  CharSlice :: from ( "0x0000000000001234" ) , 
251+                 code :  1 , 
252+                 code_human_readable :  datadog_crashtracker:: SiCodes :: SEGV_BNDERR , 
253+                 signo :  11 , 
254+                 signo_human_readable :  datadog_crashtracker:: SignalNames :: SIGSEGV , 
255+             } ; 
256+ 
257+             let  result = ddog_crasht_PingInfoBuilder_with_sig_info ( & mut  builder,  sig_info) ; 
258+             match  result { 
259+                 ddcommon_ffi:: VoidResult :: Ok  => { } , 
260+                 ddcommon_ffi:: VoidResult :: Err ( _)  => panic ! ( "Failed to set sig_info" ) , 
261+             } 
262+ 
263+             // Add insights 
264+             let  result = ddog_crasht_PingInfoBuilder_with_os_info_this_machine ( & mut  builder) ; 
265+             match  result { 
266+                 ddcommon_ffi:: VoidResult :: Ok  => { } , 
267+                 ddcommon_ffi:: VoidResult :: Err ( _)  => panic ! ( "Failed to set os_info" ) , 
268+             } 
269+ 
270+             let  result = ddog_crasht_PingInfoBuilder_with_proc_info ( & mut  builder) ; 
271+             match  result { 
272+                 ddcommon_ffi:: VoidResult :: Ok  => { } , 
273+                 ddcommon_ffi:: VoidResult :: Err ( _)  => panic ! ( "Failed to set proc_info" ) , 
274+             } 
275+ 
276+             // Build the ping 
277+             let  ping_result = ddog_crasht_PingInfoBuilder_build ( & mut  builder) ; 
278+             let  mut  ping = match  ping_result { 
279+                 PingInfoNewResult :: Ok ( p)  => p, 
280+                 PingInfoNewResult :: Err ( _)  => panic ! ( "Failed to build ping info" ) , 
281+             } ; 
282+ 
283+             // Upload - for testing we'll pass null endpoint to use builder's endpoint 
284+             let  result = ddog_crasht_PingInfo_upload_to_endpoint ( & mut  ping,  std:: ptr:: null ( ) ) ; 
285+             match  result { 
286+                 ddcommon_ffi:: VoidResult :: Ok  => { } , 
287+                 ddcommon_ffi:: VoidResult :: Err ( _)  => { 
288+                     // Expected to fail since we don't have a real endpoint, that's okay 
289+                 } 
290+             } 
291+ 
292+             // Cleanup 
293+             ddog_crasht_PingInfo_drop ( & mut  ping) ; 
294+             ddog_crasht_PingInfoBuilder_drop ( & mut  builder) ; 
295+         } 
296+     } 
297+ } 
0 commit comments