| 1 | //! High layer providing automatic marshalling of Rust closures |
| 2 | //! as C function pointers. |
| 3 | //! |
| 4 | //! The main facility here is given by the structs |
| 5 | //! <code>Closure<em>N</em></code>, |
| 6 | //! <code>Closure<span></span>Mut<em>N</em></code>, |
| 7 | //! and <code>Closure<span></span>Once<em>N</em></code>, |
| 8 | //! for natural numbers *`N`* |
| 9 | //! from `0` to `12` (as of |
| 10 | //! now). These represent C closures of *`N`* arguments, which can be |
| 11 | //! used to turn Rust lambdas (or in generally, anything that implements |
| 12 | //! `Fn` or `FnMut`) into ordinary C function pointers. For example, a |
| 13 | //! Rust value of type `Fn(u32, u32) -> u64` can be turned into a |
| 14 | //! closure of type [`Closure2<u32, u32, u64>`] using |
| 15 | //! [`Closure2::new`]. Then a C |
| 16 | //! function pointer of type `extern "C" fn(u32, u32) -> u64` can be |
| 17 | //! borrowed from the closure and passed to C. |
| 18 | //! |
| 19 | //! The above usage case eliminates much of the boilerplate involved in |
| 20 | //! creating a closure as compared to the `middle` and `low` layers, but |
| 21 | //! at the price of flexibility. Some flexibility can be recovered by |
| 22 | //! manually constructing and configuring a CIF (*e.g.,* a |
| 23 | //! [`Cif2`]) and then creating the closure with |
| 24 | //! [`Closure2::new_with_cif`]. |
| 25 | //! |
| 26 | //! See the [`mod@call`] submodule for a simple interface |
| 27 | //! to dynamic calls to C functions. |
| 28 | //! |
| 29 | //! # Examples |
| 30 | //! |
| 31 | //! Here we use [`ClosureMut1`], which is the type |
| 32 | //! for creating mutable closures of one argument. We use it to turn a |
| 33 | //! Rust lambda into a C function pointer. |
| 34 | //! |
| 35 | //! ``` |
| 36 | //! use libffi::high::ClosureMut1; |
| 37 | //! |
| 38 | //! let mut x = 0u64; |
| 39 | //! let mut f = |y: u32| { x += y as u64; x }; |
| 40 | //! |
| 41 | //! let closure = ClosureMut1::new(&mut f); |
| 42 | //! let counter = closure.code_ptr(); |
| 43 | //! |
| 44 | //! assert_eq!(5, counter.call(5)); |
| 45 | //! assert_eq!(6, counter.call(1)); |
| 46 | //! assert_eq!(8, counter.call(2)); |
| 47 | //! ``` |
| 48 | //! |
| 49 | //! Note that in the above example, `counter` is an ordinary C function |
| 50 | //! pointer of type `extern "C" fn(u64) -> u64`. |
| 51 | //! |
| 52 | //! Here’s an example using `ClosureOnce3` to create a closure that owns |
| 53 | //! a vector: |
| 54 | //! |
| 55 | //! ``` |
| 56 | //! use libffi::high::ClosureOnce3; |
| 57 | //! |
| 58 | //! let v = vec![1, 2, 3, 4, 5]; |
| 59 | //! let mut f = move |x: usize, y: usize, z: usize| { |
| 60 | //! v[x] + v[y] + v[z] |
| 61 | //! }; |
| 62 | //! |
| 63 | //! let closure = ClosureOnce3::new(f); |
| 64 | //! let call = closure.code_ptr(); |
| 65 | //! |
| 66 | //! assert_eq!(12, call.call(2, 3, 4)); |
| 67 | //! ``` |
| 68 | //! |
| 69 | //! Invoking the closure a second time will panic. |
| 70 | |
| 71 | pub use crate::middle::{ffi_abi_FFI_DEFAULT_ABI, FfiAbi}; |
| 72 | |
| 73 | pub mod types; |
| 74 | pub use types::{CType, Type}; |
| 75 | |
| 76 | pub mod call; |
| 77 | pub use call::*; |
| 78 | |
| 79 | macro_rules! abort_on_panic { |
| 80 | ($msg:literal, $body:expr) => {{ |
| 81 | // Aborts when dropped (which will only happen due to an unwinding panic). |
| 82 | struct Bomb; |
| 83 | impl Drop for Bomb { |
| 84 | fn drop(&mut self) { |
| 85 | // We do our best to ignore errors that occur during printing. |
| 86 | // If this panics anyway, that'll still just be a double-panic which leads to abort. |
| 87 | let _ = writeln!(std::io::stderr(), $msg); |
| 88 | std::process::abort(); |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | let b = Bomb; |
| 93 | // If this panics, `b` will be dropped, triggering the bomb. |
| 94 | $body; |
| 95 | // Defuse the bomb. |
| 96 | std::mem::forget(b); |
| 97 | }}; |
| 98 | } |
| 99 | |
| 100 | macro_rules! define_closure_mod { |
| 101 | ( |
| 102 | $module:ident $cif:ident $fnptr:ident |
| 103 | $callback:ident $callback_mut:ident $callback_once:ident |
| 104 | $closure:ident $closure_mut:ident $closure_once:ident; |
| 105 | $( $T:ident )* |
| 106 | ) |
| 107 | => |
| 108 | { |
| 109 | /// CIF and closure types organized by function arity. |
| 110 | #[allow(clippy::too_many_arguments)] |
| 111 | pub mod $module { |
| 112 | use std::any::Any; |
| 113 | use std::marker::PhantomData; |
| 114 | use std::{mem, process, ptr}; |
| 115 | use std::io::{self, Write}; |
| 116 | |
| 117 | use super::*; |
| 118 | use crate::{low, middle}; |
| 119 | |
| 120 | /// A typed CIF, which statically tracks argument and result types. |
| 121 | pub struct $cif<$( $T, )* R> { |
| 122 | untyped: middle::Cif, |
| 123 | _marker: PhantomData<fn($( $T, )*) -> R>, |
| 124 | } |
| 125 | |
| 126 | impl<$( $T, )* R> $cif<$( $T, )* R> { |
| 127 | /// Creates a new statically-typed CIF with the given argument |
| 128 | /// and result types. |
| 129 | #[allow(non_snake_case)] |
| 130 | pub fn new($( $T: Type<$T>, )* result: Type<R>) -> Self { |
| 131 | let cif = middle::Cif::new( |
| 132 | vec![$( $T.into_middle() ),*].into_iter(), |
| 133 | result.into_middle()); |
| 134 | $cif { untyped: cif, _marker: PhantomData } |
| 135 | } |
| 136 | |
| 137 | /// Sets the CIF to use the given calling convention. |
| 138 | pub fn set_abi(&mut self, abi: FfiAbi) { |
| 139 | self.untyped.set_abi(abi); |
| 140 | } |
| 141 | } |
| 142 | |
| 143 | impl<$( $T: CType, )* R: CType> $cif<$( $T, )* R> { |
| 144 | /// Creates a new statically-typed CIF by reifying the |
| 145 | /// argument types as `Type<T>`s. |
| 146 | pub fn reify() -> Self { |
| 147 | Self::new($( $T::reify(), )* R::reify()) |
| 148 | } |
| 149 | } |
| 150 | |
| 151 | /// A lifetime carrying wrapper type for [`fn`] pointers. |
| 152 | #[derive(Clone, Copy)] |
| 153 | #[repr(transparent)] |
| 154 | pub struct $fnptr<'a, $( $T, )* R> { |
| 155 | func: extern "C" fn($( $T, )*) -> R, |
| 156 | _lifetime: PhantomData<&'a extern "C" fn($( $T, )*) -> R>, |
| 157 | } |
| 158 | impl<'a, $( $T, )* R> $fnptr<'a, $( $T, )* R> { |
| 159 | /// Call the wrapped [`fn`] pointer. |
| 160 | // We allow non snake case variable identifiers here because |
| 161 | // we would otherwise need to take in a whole new list of |
| 162 | // argument identifiers at every invocation of this macro, |
| 163 | // and there would be no gain from doing so, since the parameter |
| 164 | // names here are entirely meaningless. |
| 165 | #[allow(non_snake_case)] |
| 166 | pub fn call(&self, $( $T : $T, )*) -> R { |
| 167 | (self.func)($( $T, )*) |
| 168 | } |
| 169 | } |
| 170 | |
| 171 | // We use tuples of pointers to describe the arguments, and we |
| 172 | // extract them by pattern matching. This assumes that a tuple |
| 173 | // of pointers will be laid out packed and in order. This seems |
| 174 | // to hold true right now, and I can’t think of a reason why it |
| 175 | // wouldn’t be that way, but technically it may be undefined |
| 176 | // behavior. |
| 177 | |
| 178 | /// The type of function called from an immutable, typed closure. |
| 179 | pub type $callback<U, $( $T, )* R> |
| 180 | = extern "C" fn(cif: &low::ffi_cif, |
| 181 | result: &mut R, |
| 182 | args: &($( &$T, )*), |
| 183 | userdata: &U); |
| 184 | |
| 185 | /// An immutable, typed closure with the given argument and result |
| 186 | /// types. |
| 187 | pub struct $closure<'a, $( $T, )* R> { |
| 188 | untyped: middle::Closure<'a>, |
| 189 | _marker: PhantomData<fn($( $T, )*) -> R>, |
| 190 | } |
| 191 | |
| 192 | impl<'a, $($T: CType,)* R: CType> $closure<'a, $($T,)* R> { |
| 193 | /// Constructs a typed closure callable from C from a |
| 194 | /// Rust closure. |
| 195 | pub fn new<Callback>(callback: &'a Callback) -> Self |
| 196 | where Callback: Fn($( $T, )*) -> R + 'a |
| 197 | { |
| 198 | Self::new_with_cif($cif::reify(), callback) |
| 199 | } |
| 200 | } |
| 201 | |
| 202 | impl<'a, $( $T, )* R: CType> $closure<'a, $( $T, )* R> { |
| 203 | /// Gets the C code pointer that is used to invoke the |
| 204 | /// closure. |
| 205 | pub fn code_ptr(&self) -> & $fnptr <'a, $( $T, )* R> { |
| 206 | // Safety: Here we produce an FnPtrN wrapper for |
| 207 | // the correct `fn` pointer, which is repr(transparent) |
| 208 | // and therefore reference, layout, and otherwise ABI compatible |
| 209 | // with that type. |
| 210 | // Additionally, the FnPtrN wrapper enforces usage of the returned |
| 211 | // function pointer be only within the lifetime of the closure |
| 212 | // from which it was made. |
| 213 | // Other safety invariants have not been checked by |
| 214 | // the author of this comment, see the `instantiate_code_ptr` |
| 215 | // method docs for more. |
| 216 | unsafe { |
| 217 | self.untyped.instantiate_code_ptr() |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | /// Constructs a typed closure callable from C from a CIF |
| 222 | /// describing the calling convention for the resulting |
| 223 | /// function, a callback for the function to call, and |
| 224 | /// userdata to pass to the callback. Note that the return |
| 225 | /// type of the callback must follow the libffi implicit |
| 226 | /// extension rules. |
| 227 | pub fn from_parts<U>(cif: $cif<$( $T, )* R>, |
| 228 | callback: $callback<U, $( $T, )* R::RetType>, |
| 229 | userdata: &'a U) -> Self |
| 230 | { |
| 231 | let callback: middle::Callback<U, R::RetType> |
| 232 | = unsafe { mem::transmute(callback) }; |
| 233 | let closure |
| 234 | = middle::Closure::new(cif.untyped, |
| 235 | callback, |
| 236 | userdata); |
| 237 | $closure { |
| 238 | untyped: closure, |
| 239 | _marker: PhantomData, |
| 240 | } |
| 241 | } |
| 242 | } |
| 243 | |
| 244 | impl<'a, $( $T: Copy, )* R: CType> $closure<'a, $( $T, )* R> { |
| 245 | /// Constructs a typed closure callable from C from a CIF |
| 246 | /// describing the calling convention for the resulting |
| 247 | /// function and the Rust closure to call. |
| 248 | pub fn new_with_cif<Callback>(cif: $cif<$( $T, )* R>, |
| 249 | callback: &'a Callback) -> Self |
| 250 | where Callback: Fn($( $T, )*) -> R + 'a |
| 251 | { |
| 252 | Self::from_parts(cif, |
| 253 | Self::static_callback, |
| 254 | callback) |
| 255 | } |
| 256 | |
| 257 | #[allow(non_snake_case)] |
| 258 | extern "C" fn static_callback<Callback> |
| 259 | (_cif: &low::ffi_cif, |
| 260 | result: &mut R::RetType, |
| 261 | &($( &$T, )*): |
| 262 | &($( &$T, )*), |
| 263 | userdata: &Callback) |
| 264 | where Callback: Fn($( $T, )*) -> R + 'a |
| 265 | { |
| 266 | abort_on_panic!("Cannot panic inside FFI callback" , { |
| 267 | unsafe { |
| 268 | ptr::write(result, userdata($( $T, )*).into()); |
| 269 | } |
| 270 | }); |
| 271 | } |
| 272 | } |
| 273 | |
| 274 | /// The type of function called from a mutable, typed closure. |
| 275 | pub type $callback_mut<U, $( $T, )* R> |
| 276 | = extern "C" fn(cif: &low::ffi_cif, |
| 277 | result: &mut R, |
| 278 | args: &($( &$T, )*), |
| 279 | userdata: &mut U); |
| 280 | |
| 281 | /// A mutable, typed closure with the given argument and |
| 282 | /// result types. |
| 283 | pub struct $closure_mut<'a, $( $T, )* R> { |
| 284 | untyped: middle::Closure<'a>, |
| 285 | _marker: PhantomData<fn($( $T, )*) -> R>, |
| 286 | } |
| 287 | |
| 288 | impl<'a, $($T: CType,)* R: CType> |
| 289 | $closure_mut<'a, $($T,)* R> |
| 290 | { |
| 291 | /// Constructs a typed closure callable from C from a |
| 292 | /// Rust closure. |
| 293 | pub fn new<Callback>(callback: &'a mut Callback) -> Self |
| 294 | where Callback: FnMut($( $T, )*) -> R + 'a |
| 295 | { |
| 296 | Self::new_with_cif($cif::reify(), callback) |
| 297 | } |
| 298 | } |
| 299 | |
| 300 | impl<'a, $( $T, )* R: CType> $closure_mut<'a, $( $T, )* R> { |
| 301 | /// Gets the C code pointer that is used to invoke the |
| 302 | /// closure. |
| 303 | pub fn code_ptr(&self) -> & $fnptr <'a, $( $T, )* R> { |
| 304 | unsafe { |
| 305 | self.untyped.instantiate_code_ptr() |
| 306 | } |
| 307 | } |
| 308 | |
| 309 | /// Constructs a typed closure callable from C from a CIF |
| 310 | /// describing the calling convention for the resulting |
| 311 | /// function, a callback for the function to call, and |
| 312 | /// userdata to pass to the callback. Note that the return |
| 313 | /// type of the callback must follow the libffi implicit |
| 314 | /// extension rules. |
| 315 | pub fn from_parts<U>(cif: $cif<$( $T, )* R>, |
| 316 | callback: $callback_mut<U, $( $T, )* R::RetType>, |
| 317 | userdata: &'a mut U) -> Self |
| 318 | { |
| 319 | let callback: middle::CallbackMut<U, R::RetType> |
| 320 | = unsafe { mem::transmute(callback) }; |
| 321 | let closure |
| 322 | = middle::Closure::new_mut(cif.untyped, |
| 323 | callback, |
| 324 | userdata); |
| 325 | $closure_mut { |
| 326 | untyped: closure, |
| 327 | _marker: PhantomData, |
| 328 | } |
| 329 | } |
| 330 | } |
| 331 | |
| 332 | impl<'a, $( $T: Copy, )* R: CType> $closure_mut<'a, $( $T, )* R> { |
| 333 | /// Constructs a typed closure callable from C from a CIF |
| 334 | /// describing the calling convention for the resulting |
| 335 | /// function and the Rust closure to call. |
| 336 | pub fn new_with_cif<Callback>(cif: $cif<$( $T, )* R>, |
| 337 | callback: &'a mut Callback) |
| 338 | -> Self |
| 339 | where Callback: FnMut($( $T, )*) -> R + 'a |
| 340 | { |
| 341 | Self::from_parts(cif, |
| 342 | Self::static_callback, |
| 343 | callback) |
| 344 | } |
| 345 | |
| 346 | #[allow(non_snake_case)] |
| 347 | extern "C" fn static_callback<Callback> |
| 348 | (_cif: &low::ffi_cif, |
| 349 | result: &mut R::RetType, |
| 350 | &($( &$T, )*): |
| 351 | &($( &$T, )*), |
| 352 | userdata: &mut Callback) |
| 353 | where Callback: FnMut($( $T, )*) -> R + 'a |
| 354 | { |
| 355 | abort_on_panic!("Cannot panic inside FFI callback" , { |
| 356 | unsafe { |
| 357 | ptr::write(result, userdata($( $T, )*).into()); |
| 358 | } |
| 359 | }); |
| 360 | } |
| 361 | } |
| 362 | |
| 363 | /// The type of function called from a one-shot, typed closure. |
| 364 | pub type $callback_once<U, $( $T, )* R> |
| 365 | = $callback_mut<Option<U>, $( $T, )* R>; |
| 366 | |
| 367 | /// A one-shot, typed closure with the given argument and |
| 368 | /// result types. |
| 369 | pub struct $closure_once<$( $T, )* R> { |
| 370 | untyped: middle::ClosureOnce, |
| 371 | _marker: PhantomData<fn($( $T, )*) -> R>, |
| 372 | } |
| 373 | |
| 374 | impl<$($T: CType,)* R: CType> $closure_once<$($T,)* R> { |
| 375 | /// Constructs a typed closure callable from C from a |
| 376 | /// Rust closure. |
| 377 | pub fn new<Callback>(callback: Callback) -> Self |
| 378 | where Callback: FnOnce($( $T, )*) -> R + Any |
| 379 | { |
| 380 | Self::new_with_cif($cif::reify(), callback) |
| 381 | } |
| 382 | } |
| 383 | |
| 384 | impl<$( $T: Copy, )* R: CType> $closure_once<$( $T, )* R> { |
| 385 | /// Constructs a one-shot closure callable from C from a CIF |
| 386 | /// describing the calling convention for the resulting |
| 387 | /// function and the Rust closure to call. |
| 388 | pub fn new_with_cif<Callback>(cif: $cif<$( $T, )* R>, |
| 389 | callback: Callback) -> Self |
| 390 | where Callback: FnOnce($( $T, )*) -> R + Any |
| 391 | { |
| 392 | Self::from_parts(cif, |
| 393 | Self::static_callback, |
| 394 | callback) |
| 395 | } |
| 396 | |
| 397 | #[allow(non_snake_case)] |
| 398 | extern "C" fn static_callback<Callback> |
| 399 | (_cif: &low::ffi_cif, |
| 400 | result: &mut R::RetType, |
| 401 | &($( &$T, )*): |
| 402 | &($( &$T, )*), |
| 403 | userdata: &mut Option<Callback>) |
| 404 | where Callback: FnOnce($( $T, )*) -> R |
| 405 | { |
| 406 | if let Some(userdata) = userdata.take() { |
| 407 | abort_on_panic!("Cannot panic inside FFI callback" , { |
| 408 | unsafe { |
| 409 | ptr::write(result, userdata($( $T, )*).into()); |
| 410 | } |
| 411 | }); |
| 412 | } else { |
| 413 | // There is probably a better way to abort here. |
| 414 | let _ = |
| 415 | io::stderr().write(b"FnOnce closure already used" ); |
| 416 | process::exit(2); |
| 417 | } |
| 418 | } |
| 419 | } |
| 420 | |
| 421 | impl<$( $T, )* R: CType> $closure_once<$( $T, )* R> { |
| 422 | /// Gets the C code pointer that is used to invoke the |
| 423 | /// closure. |
| 424 | pub fn code_ptr(&self) -> & $fnptr <'_, $( $T, )* R> { |
| 425 | unsafe { |
| 426 | self.untyped.instantiate_code_ptr() |
| 427 | } |
| 428 | } |
| 429 | |
| 430 | /// Constructs a one-shot closure callable from C from a CIF |
| 431 | /// describing the calling convention for the resulting |
| 432 | /// function, a callback for the function to call, and |
| 433 | /// userdata to pass to the callback. Note that the return |
| 434 | /// type of the callback must follow the libffi implicit |
| 435 | /// extension rules. |
| 436 | pub fn from_parts<U: Any>( |
| 437 | cif: $cif<$( $T, )* R>, |
| 438 | callback: $callback_once<U, $( $T, )* R::RetType>, |
| 439 | userdata: U) |
| 440 | -> Self |
| 441 | { |
| 442 | let callback: middle::CallbackOnce<U, R::RetType> |
| 443 | = unsafe { mem::transmute(callback) }; |
| 444 | let closure |
| 445 | = middle::ClosureOnce::new(cif.untyped, |
| 446 | callback, |
| 447 | userdata); |
| 448 | $closure_once { |
| 449 | untyped: closure, |
| 450 | _marker: PhantomData, |
| 451 | } |
| 452 | } |
| 453 | } |
| 454 | } |
| 455 | |
| 456 | pub use $module::*; |
| 457 | } |
| 458 | } |
| 459 | |
| 460 | define_closure_mod!(arity0 Cif0 FnPtr0 |
| 461 | Callback0 CallbackMut0 CallbackOnce0 |
| 462 | Closure0 ClosureMut0 ClosureOnce0; |
| 463 | ); |
| 464 | define_closure_mod!(arity1 Cif1 FnPtr1 |
| 465 | Callback1 CallbackMut1 CallbackOnce1 |
| 466 | Closure1 ClosureMut1 ClosureOnce1; |
| 467 | A); |
| 468 | define_closure_mod!(arity2 Cif2 FnPtr2 |
| 469 | Callback2 CallbackMut2 CallbackOnce2 |
| 470 | Closure2 ClosureMut2 ClosureOnce2; |
| 471 | A B); |
| 472 | define_closure_mod!(arity3 Cif3 FnPtr3 |
| 473 | Callback3 CallbackMut3 CallbackOnce3 |
| 474 | Closure3 ClosureMut3 ClosureOnce3; |
| 475 | A B C); |
| 476 | define_closure_mod!(arity4 Cif4 FnPtr4 |
| 477 | Callback4 CallbackMut4 CallbackOnce4 |
| 478 | Closure4 ClosureMut4 ClosureOnce4; |
| 479 | A B C D); |
| 480 | define_closure_mod!(arity5 Cif5 FnPtr5 |
| 481 | Callback5 CallbackMut5 CallbackOnce5 |
| 482 | Closure5 ClosureMut5 ClosureOnce5; |
| 483 | A B C D E); |
| 484 | define_closure_mod!(arity6 Cif6 FnPtr6 |
| 485 | Callback6 CallbackMut6 CallbackOnce6 |
| 486 | Closure6 ClosureMut6 ClosureOnce6; |
| 487 | A B C D E F); |
| 488 | define_closure_mod!(arity7 Cif7 FnPtr7 |
| 489 | Callback7 CallbackMut7 CallbackOnce7 |
| 490 | Closure7 ClosureMut7 ClosureOnce7; |
| 491 | A B C D E F G); |
| 492 | define_closure_mod!(arity8 Cif8 FnPtr8 |
| 493 | Callback8 CallbackMut8 CallbackOnce8 |
| 494 | Closure8 ClosureMut8 ClosureOnce8; |
| 495 | A B C D E F G H); |
| 496 | define_closure_mod!(arity9 Cif9 FnPtr9 |
| 497 | Callback9 CallbackMut9 CallbackOnce9 |
| 498 | Closure9 ClosureMut9 ClosureOnce9; |
| 499 | A B C D E F G H I); |
| 500 | define_closure_mod!(arity10 Cif10 FnPtr10 |
| 501 | Callback10 CallbackMut10 CallbackOnce10 |
| 502 | Closure10 ClosureMut10 ClosureOnce10; |
| 503 | A B C D E F G H I J); |
| 504 | define_closure_mod!(arity11 Cif11 FnPtr11 |
| 505 | Callback11 CallbackMut11 CallbackOnce11 |
| 506 | Closure11 ClosureMut11 ClosureOnce11; |
| 507 | A B C D E F G H I J K); |
| 508 | define_closure_mod!(arity12 Cif12 FnPtr12 |
| 509 | Callback12 CallbackMut12 CallbackOnce12 |
| 510 | Closure12 ClosureMut12 ClosureOnce12; |
| 511 | A B C D E F G H I J K L); |
| 512 | |
| 513 | #[cfg (test)] |
| 514 | mod test { |
| 515 | use super::*; |
| 516 | |
| 517 | #[test ] |
| 518 | fn new_with_cif() { |
| 519 | let x: u64 = 1; |
| 520 | let f = |y: u64, z: u64| x + y + z; |
| 521 | |
| 522 | let type_ = u64::reify(); |
| 523 | let cif = Cif2::new(type_.clone(), type_.clone(), type_.clone()); |
| 524 | let closure = Closure2::new_with_cif(cif, &f); |
| 525 | |
| 526 | assert_eq!(12, closure.code_ptr().call(5, 6)); |
| 527 | } |
| 528 | |
| 529 | #[test ] |
| 530 | fn new_with_cif_mut() { |
| 531 | let mut x: u64 = 0; |
| 532 | let mut f = |y: u64| { |
| 533 | x += y; |
| 534 | x |
| 535 | }; |
| 536 | |
| 537 | let type_ = u64::reify(); |
| 538 | let cif = Cif1::new(type_.clone(), type_.clone()); |
| 539 | let closure = ClosureMut1::new_with_cif(cif, &mut f); |
| 540 | |
| 541 | let counter = closure.code_ptr(); |
| 542 | |
| 543 | assert_eq!(5, counter.call(5)); |
| 544 | assert_eq!(6, counter.call(1)); |
| 545 | assert_eq!(8, counter.call(2)); |
| 546 | } |
| 547 | |
| 548 | #[test ] |
| 549 | fn new() { |
| 550 | let x: u64 = 1; |
| 551 | let f = |y: u64, z: u64| x + y + z; |
| 552 | |
| 553 | let closure = Closure2::new(&f); |
| 554 | |
| 555 | assert_eq!(12, closure.code_ptr().call(5, 6)); |
| 556 | } |
| 557 | |
| 558 | #[test ] |
| 559 | fn new_mut() { |
| 560 | let mut x: u64 = 0; |
| 561 | let mut f = |y: u32| { |
| 562 | x += u64::from(y); |
| 563 | x |
| 564 | }; |
| 565 | |
| 566 | let closure = ClosureMut1::new(&mut f); |
| 567 | let counter = closure.code_ptr(); |
| 568 | |
| 569 | assert_eq!(5, counter.call(5)); |
| 570 | assert_eq!(6, counter.call(1)); |
| 571 | assert_eq!(8, counter.call(2)); |
| 572 | } |
| 573 | } |
| 574 | |