@@ -29,6 +29,17 @@ impl nickel_context {
29
29
}
30
30
}
31
31
32
+ /// A Nickel error.
33
+ ///
34
+ /// If you want to collect an error message from a fallible function
35
+ /// (like `nickel_context_eval_deep`), first allocate an error using
36
+ /// `nickel_error_alloc`, and then pass the resulting pointer to your fallible
37
+ /// function. If that function fails, it will save the error data in your
38
+ /// `nickel_error`.
39
+ pub struct nickel_error {
40
+ inner : Option < Error > ,
41
+ }
42
+
32
43
/// A Nickel expression.
33
44
///
34
45
/// This might be fully evaluated (for example, if you got it from [`nickel_context_eval_deep`])
@@ -105,6 +116,15 @@ impl<'a> From<Record<'a>> for *const nickel_record {
105
116
}
106
117
}
107
118
119
+ /// A Nickel string.
120
+ // It would be nice to put `repr(transparent)` here, but (1) we don't
121
+ // actually need to cast `String` pointers to `nickel_string` pointers,
122
+ // and (2) adding `repr(transparent)` makes cbindgen expose `String`
123
+ // even though it's private.
124
+ pub struct nickel_string {
125
+ inner : String ,
126
+ }
127
+
108
128
/// A Nickel number.
109
129
///
110
130
/// See [`nickel_expr_is_number`] and [`nickel_expr_as_number`].
@@ -153,11 +173,14 @@ pub unsafe extern "C" fn nickel_context_free(ctx: *mut nickel_context) {
153
173
/// This function will be called with a buffer (`buf`) of data, having length
154
174
/// `len`. It need not consume the entire buffer, and should return the number
155
175
/// of bytes consumed.
176
+ // This Option<fn> pattern seems to be cbindgen's preferred way of encoding
177
+ // a nullable function pointer (since rust fns are never null).
178
+ // https://github.com/mozilla/cbindgen/issues/326#issuecomment-584288686
156
179
pub type nickel_write_callback =
157
- extern "C" fn ( context : * const c_void , buf : * const u8 , len : usize ) -> usize ;
180
+ Option < extern "C" fn ( context : * const c_void , buf : * const u8 , len : usize ) -> usize > ;
158
181
159
182
/// A callback function for flushing data that was written by a write callback.
160
- pub type nickel_flush_callback = extern "C" fn ( context : * const c_void ) ;
183
+ pub type nickel_flush_callback = Option < extern "C" fn ( context : * const c_void ) > ;
161
184
162
185
/// For functions that can fail, these are the interpretations of the return value.
163
186
#[ repr( C ) ]
@@ -170,13 +193,17 @@ pub enum nickel_result {
170
193
171
194
struct CTrace {
172
195
write : nickel_write_callback ,
173
- flush : Option < nickel_flush_callback > ,
196
+ flush : nickel_flush_callback ,
174
197
context : * const c_void ,
175
198
}
176
199
177
200
impl Write for CTrace {
178
201
fn write ( & mut self , buf : & [ u8 ] ) -> std:: io:: Result < usize > {
179
- let count = ( self . write ) ( self . context , buf. as_ptr ( ) , buf. len ( ) ) ;
202
+ let count = if let Some ( w) = self . write {
203
+ w ( self . context , buf. as_ptr ( ) , buf. len ( ) )
204
+ } else {
205
+ buf. len ( )
206
+ } ;
180
207
if count == usize:: MAX {
181
208
Err ( std:: io:: Error :: other ( "trace failed to write" ) )
182
209
} else {
@@ -198,8 +225,7 @@ impl Write for CTrace {
198
225
pub unsafe extern "C" fn nickel_context_set_trace_callback (
199
226
mut ctx : * mut nickel_context ,
200
227
write : nickel_write_callback ,
201
- // TODO: if this is non-optional, are they allowed to pass NULL?
202
- flush : Option < nickel_flush_callback > ,
228
+ flush : nickel_flush_callback ,
203
229
user_data : * const c_void ,
204
230
) {
205
231
let trace = Trace :: new ( CTrace {
@@ -232,7 +258,7 @@ unsafe fn do_eval<F: FnOnce(&mut crate::Context, &str) -> Result<Expr, Error>>(
232
258
mut ctx : * mut nickel_context ,
233
259
src : * const c_char ,
234
260
mut out_expr : * mut nickel_expr ,
235
- out_error : * mut * mut Error ,
261
+ out_error : * mut nickel_error ,
236
262
) -> nickel_result {
237
263
let src = CStr :: from_ptr ( src) . to_str ( ) . unwrap ( ) ;
238
264
match f ( nickel_context:: as_rust_mut ( & mut ctx) , src) {
@@ -244,7 +270,7 @@ unsafe fn do_eval<F: FnOnce(&mut crate::Context, &str) -> Result<Expr, Error>>(
244
270
}
245
271
Err ( e) => {
246
272
if !out_error. is_null ( ) {
247
- * out_error = Box :: into_raw ( Box :: new ( e ) ) ;
273
+ ( * out_error) . inner = Some ( e ) ;
248
274
}
249
275
nickel_result:: NICKEL_RESULT_ERR
250
276
}
@@ -273,7 +299,7 @@ pub unsafe extern "C" fn nickel_context_eval_deep(
273
299
ctx : * mut nickel_context ,
274
300
src : * const c_char ,
275
301
out_expr : * mut nickel_expr ,
276
- out_error : * mut * mut Error ,
302
+ out_error : * mut nickel_error ,
277
303
) -> nickel_result {
278
304
do_eval ( |ctx, src| ctx. eval_deep ( src) , ctx, src, out_expr, out_error)
279
305
}
@@ -300,7 +326,7 @@ pub unsafe extern "C" fn nickel_context_eval_deep_for_export(
300
326
ctx : * mut nickel_context ,
301
327
src : * const c_char ,
302
328
out_expr : * mut nickel_expr ,
303
- out_error : * mut * mut Error ,
329
+ out_error : * mut nickel_error ,
304
330
) -> nickel_result {
305
331
do_eval (
306
332
|ctx, src| ctx. eval_deep_for_export ( src) ,
@@ -343,7 +369,7 @@ pub unsafe extern "C" fn nickel_context_eval_shallow(
343
369
src : * const c_char ,
344
370
mut out_expr : * mut nickel_expr ,
345
371
out_virtual_machine : * mut nickel_virtual_machine ,
346
- out_error : * mut * mut Error ,
372
+ out_error : * mut nickel_error ,
347
373
) -> nickel_result {
348
374
let src = CStr :: from_ptr ( src) . to_str ( ) . unwrap ( ) ;
349
375
match nickel_context:: as_rust_mut ( & mut ctx) . eval_shallow ( src) {
@@ -358,19 +384,13 @@ pub unsafe extern "C" fn nickel_context_eval_shallow(
358
384
}
359
385
Err ( e) => {
360
386
if !out_error. is_null ( ) {
361
- * out_error = Box :: into_raw ( Box :: new ( e ) ) ;
387
+ ( * out_error) . inner = Some ( e ) ;
362
388
}
363
389
nickel_result:: NICKEL_RESULT_ERR
364
390
}
365
391
}
366
392
}
367
393
368
- /// Frees a Nickel error message.
369
- #[ no_mangle]
370
- pub unsafe extern "C" fn nickel_error_free ( err : * mut Error ) {
371
- let _ = Box :: from_raw ( err) ;
372
- }
373
-
374
394
/// Allocate a new Nickel expression.
375
395
///
376
396
/// The returned expression pointer can be used to store the results of
@@ -391,16 +411,16 @@ pub unsafe extern "C" fn nickel_error_free(err: *mut Error) {
391
411
///
392
412
/// nickel_context_eval_deep(ctx, "{ foo = 1 }", expr, NULL);
393
413
///
394
- /// /* now expr is a record */
414
+ /// // now expr is a record
395
415
/// printf("record: %d\n", nickel_expr_is_record(expr));
396
416
///
397
417
/// nickel_context_eval_deep(ctx, "[1, 2, 3]", expr, NULL);
398
418
///
399
- /// /* now expr is an array */
419
+ /// // now expr is an array
400
420
/// printf("array: %d\n", nickel_expr_is_array(expr));
401
421
///
402
- /// /* the calls to nickel_context_eval_deep haven't created any new exprs:
403
- /// we only need to free it once */
422
+ /// // the calls to nickel_context_eval_deep haven't created any new exprs:
423
+ /// // we only need to free it once
404
424
/// nickel_expr_free(expr);
405
425
/// nickel_context_free(ctx);
406
426
/// ```
@@ -650,12 +670,12 @@ pub unsafe extern "C" fn nickel_number_as_f64(num: *const nickel_number) -> f64
650
670
#[ no_mangle]
651
671
pub unsafe extern "C" fn nickel_number_as_rational (
652
672
num : * const nickel_number ,
653
- out_numerator : * mut String ,
654
- out_denominator : * mut String ,
673
+ out_numerator : * mut nickel_string ,
674
+ out_denominator : * mut nickel_string ,
655
675
) {
656
676
let ( numerator, denominator) = nickel_number:: as_rust ( & num) . as_rational ( ) ;
657
- * out_numerator = numerator;
658
- * out_denominator = denominator;
677
+ * out_numerator = nickel_string { inner : numerator } ;
678
+ * out_denominator = nickel_string { inner : denominator } ;
659
679
}
660
680
661
681
/// The number of elements of this Nickel array.
@@ -748,13 +768,15 @@ pub unsafe extern "C" fn nickel_record_value_by_name(
748
768
/// (see `nickel_expr_alloc`). It gets allocated here, modified by various other
749
769
/// functions, and finally is freed by a call to `nickel_string_free`.
750
770
#[ no_mangle]
751
- pub unsafe extern "C" fn nickel_string_alloc ( ) -> * mut String {
752
- Box :: into_raw ( Box :: new ( String :: new ( ) ) )
771
+ pub unsafe extern "C" fn nickel_string_alloc ( ) -> * mut nickel_string {
772
+ Box :: into_raw ( Box :: new ( nickel_string {
773
+ inner : String :: new ( ) ,
774
+ } ) )
753
775
}
754
776
755
777
/// Frees a string.
756
778
#[ no_mangle]
757
- pub unsafe extern "C" fn nickel_string_free ( s : * mut String ) {
779
+ pub unsafe extern "C" fn nickel_string_free ( s : * mut nickel_string ) {
758
780
let _ = Box :: from_raw ( s) ;
759
781
}
760
782
@@ -766,13 +788,13 @@ pub unsafe extern "C" fn nickel_string_free(s: *mut String) {
766
788
/// freed or overwritten.
767
789
#[ no_mangle]
768
790
pub unsafe extern "C" fn nickel_string_data (
769
- s : * const String ,
791
+ s : * const nickel_string ,
770
792
data : * mut * const c_char ,
771
793
len : * mut usize ,
772
794
) {
773
795
let s = s. as_ref ( ) . unwrap ( ) ;
774
- * data = s. as_ptr ( ) as * const c_char ;
775
- * len = s. len ( ) ;
796
+ * data = s. inner . as_ptr ( ) as * const c_char ;
797
+ * len = s. inner . len ( ) ;
776
798
}
777
799
778
800
/// Allocate space for a virtual machine.
@@ -803,7 +825,7 @@ pub unsafe extern "C" fn nickel_virtual_machine_eval_shallow(
803
825
vm : * mut nickel_virtual_machine ,
804
826
expr : * const nickel_expr ,
805
827
mut out_expr : * mut nickel_expr ,
806
- out_error : * mut * mut Error ,
828
+ out_error : * mut nickel_error ,
807
829
) -> nickel_result {
808
830
// We clone `expr` instead of consuming it (as the rust API does). The clone is
809
831
// cheap (it's only a refcount bump) and this makes the allocation/free pairing
@@ -830,9 +852,21 @@ pub unsafe extern "C" fn nickel_virtual_machine_eval_shallow(
830
852
}
831
853
Err ( e) => {
832
854
if !out_error. is_null ( ) {
833
- * out_error = Box :: into_raw ( Box :: new ( e ) ) ;
855
+ ( * out_error) . inner = Some ( e ) ;
834
856
}
835
857
nickel_result:: NICKEL_RESULT_ERR
836
858
}
837
859
}
838
860
}
861
+
862
+ /// Allocate a new `nickel_error`.
863
+ #[ no_mangle]
864
+ pub unsafe extern "C" fn nickel_error_alloc ( ) -> * mut nickel_error {
865
+ Box :: into_raw ( Box :: new ( nickel_error { inner : None } ) )
866
+ }
867
+
868
+ /// Frees a `nickel_error`.
869
+ #[ no_mangle]
870
+ pub unsafe extern "C" fn nickel_error_free ( err : * mut nickel_error ) {
871
+ let _ = Box :: from_raw ( err) ;
872
+ }
0 commit comments