1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//! C#-specific backend patterns for transparent exception mapping.
//!
//! The central type here is [`Try<T>`], a transparent exception converter for plugins.
//! When the C# backend encounters a function returning `Try<T>`, it automatically
//! captures exceptions and converts them into an [`ExceptionError`].
//!
//! # Example
//!
//! ```rust
//! # use interoptopus::plugin;
//! # use interoptopus_csharp::pattern::Try;
//! # use crate::interoptopus_csharp::pattern::TryExtension;
//! plugin!(MyPlugin {
//! fn foo() -> Try<u32>;
//! });
//!
//! # fn foo(plugin: &MyPlugin) -> Result<(), Box<dyn std::error::Error>>{
//! plugin.foo().ok()?;
//! # Ok(())
//! # }
//! ```
//!
//! On the C# side the following plugin code is emitted that allows callees to just return a result.
//! Should an exception happen it will be automatically caught and converted.
//!
//! ```csharp
//! partial class Plugin : IPlugin
//! {
//! public static uint Foo() { };
//! }
//! ```
//!
//! # Registering exceptions
//!
//! You can tell the builder which C# exception to map (besides `System.Exception`) with
//! `DotnetLibraryBuilder::exception()`:
//!
//! ```rust,ignore
//! # use interoptopus::inventory::ForeignInventory;
//! # use interoptopus_csharp::{DotnetLibrary, pattern::Exception};
//! # fn foo(inventory: &ForeignInventory) -> Result<(), Box<dyn std::error::Error>> {
//! let output = DotnetLibrary::builder(inventory)
//! .exception(Exception::new("System.IO.FileNotFoundException"))
//! .build()
//! .process()?;
//! # Ok(())
//! # }
//! ```
//!
//!
//! # `Try` - `Result` conversion
//!
//! Because `Try<T>` is effectively an `ffi::Result` it cannot be used with Rust's `?` operator
//! directly. [`TryExtension`] converts it into a standard result for ergonomic error propagation:
//!
//! ```rust
//! # use interoptopus_csharp::pattern::{Try, TryExtension};
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! # let result: Try<u32> = Try::Ok(42);
//! let value = result.ok()?;
//! # Ok(())
//! # }
//! ```
use ffi;
pub use ;
/// Return type that enables transparent C# exception mapping.
///
/// This is an alias for `ffi::Result<T, ExceptionError>`. When the C# backend
/// sees this as a function's return type it generates typed `catch` blocks for
/// each registered [`Exception`] and unwraps the `Result` in user-facing
/// interfaces so callers work with `T` directly.
///
/// See the [module-level docs](self) for the full story.
pub type Try<T> = Result;
/// Converts a [`Try<T>`] into a standard `Result<T, ExceptionError>`.
///
/// This is a workaround for the fact that `ffi::Result` is a 4-variant enum
/// (`Ok`, `Err`, `Panic`, `Null`) and therefore incompatible with the `?`
/// operator. Both `Panic` and `Null` are mapped to
/// [`ExceptionError::unknown()`].
/// Checks whether a string looks like `System.Exception` or `System.IO.IOException`.
const