|
| 1 | +//! Example of calling overloaded C++ arithmetic functions from Rust. |
| 2 | +
|
| 3 | +#![feature(splat, tuple_trait)] |
| 4 | +#![expect(incomplete_features)] |
| 5 | + |
| 6 | +use cpp::cpp; |
| 7 | +use std::ffi::{c_double, c_int}; |
| 8 | +use std::marker::Tuple; |
| 9 | + |
| 10 | +cpp! {{ |
| 11 | + #include <cmath> |
| 12 | +}} |
| 13 | + |
| 14 | +/// The arguments of an overloaded C++ `hypot` function. |
| 15 | +trait HypotArgs: Tuple { |
| 16 | + type Output; |
| 17 | + fn call_hypot(self) -> Self::Output; |
| 18 | +} |
| 19 | + |
| 20 | +/// Calls the overloaded C++ `std::hypot` function with the given arguments. |
| 21 | +fn hypot<Args: HypotArgs>(#[splat] args: Args) -> <Args as HypotArgs>::Output { |
| 22 | + args.call_hypot() |
| 23 | +} |
| 24 | + |
| 25 | +impl HypotArgs for (c_double, c_double) { |
| 26 | + type Output = c_double; |
| 27 | + |
| 28 | + fn call_hypot(self) -> c_double { |
| 29 | + let (x, y) = self; |
| 30 | + unsafe { |
| 31 | + cpp!([x as "double", y as "double"] -> c_double as "double" { |
| 32 | + return std::hypot(x, y); |
| 33 | + }) |
| 34 | + } |
| 35 | + } |
| 36 | +} |
| 37 | + |
| 38 | +impl HypotArgs for (c_double, c_double, c_double) { |
| 39 | + type Output = c_double; |
| 40 | + |
| 41 | + fn call_hypot(self) -> c_double { |
| 42 | + let (x, y, z) = self; |
| 43 | + unsafe { |
| 44 | + cpp!([x as "double", y as "double", z as "double"] -> c_double as "double" { |
| 45 | + return std::hypot(x, y, z); |
| 46 | + }) |
| 47 | + } |
| 48 | + } |
| 49 | +} |
| 50 | + |
| 51 | +impl HypotArgs for (c_int, c_int) { |
| 52 | + type Output = c_double; |
| 53 | + |
| 54 | + fn call_hypot(self) -> c_double { |
| 55 | + let (x, y) = self; |
| 56 | + unsafe { |
| 57 | + cpp!([x as "int", y as "int"] -> c_double as "double" { |
| 58 | + // C++ instantiates the `std::hypot<int, int>` template, which casts to `double` |
| 59 | + // before calling `std::hypot(double, double)`. |
| 60 | + return std::hypot(x, y); |
| 61 | + }) |
| 62 | + } |
| 63 | + } |
| 64 | +} |
| 65 | + |
| 66 | +impl HypotArgs for (c_int, c_int, c_int) { |
| 67 | + type Output = c_double; |
| 68 | + |
| 69 | + fn call_hypot(self) -> c_double { |
| 70 | + let (x, y, z) = self; |
| 71 | + unsafe { |
| 72 | + cpp!([x as "int", y as "int", z as "int"] -> c_double as "double" { |
| 73 | + // C++ instantiates the `std::hypot<int, int, int>` template, which casts to |
| 74 | + // `double` before calling `std::hypot(double, double, double)`. |
| 75 | + return std::hypot(x, y, z); |
| 76 | + }) |
| 77 | + } |
| 78 | + } |
| 79 | +} |
| 80 | + |
| 81 | +fn main() { |
| 82 | + // Rust doesn't have c_* literal type specifiers. |
| 83 | + println!("|(3, 4)| double = {}", hypot(3.0_f64, 4.0_f64)); |
| 84 | + println!("|(2, 3, 6)| double = {}", hypot(2.0_f64, 3.0_f64, 6.0_f64)); |
| 85 | + println!("|(3, 4)| int = {}", hypot(3_i32, 4_i32)); |
| 86 | + println!("|(2, 3, 6)| int = {}", hypot(2_i32, 3_i32, 6_i32)); |
| 87 | +} |
0 commit comments