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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//! Optional types that translate to binding with better semantics in languages supporting them.
//!
//! Patterns are purely optional. If you want to use a certain pattern in your bindings
//! you generally define one or more functions that use some of the types contained in this module.
//!
//! Backends which support a pattern will then generate _additional_ language-specific helpers
//! and bindings  for it. In any case, regardless whether a pattern is supported by a backend or not,
//! fallback bindings will be available.
//!
//! ## Pattern Usage
//!
//! Unless otherwise stated patterns are used by, well, using them in signatures. For example,
//! instead of making `x` a type `*const u8` (or similar) in the following `print` function:
//!
//! ```
//! # use interoptopus::ffi_function;
//!
//! #[ffi_function]
//! #[no_mangle]
//! pub extern "C" fn print_ptr(x: *const u8) {
//!    // Write unsafe code to convert `x
//! }
//!
//! ```
//!
//! you would instead accept an [`AsciiPointer`](crate::patterns::string::AsciiPointer):
//!
//! ```
//! # use interoptopus::ffi_function;
//! # use interoptopus::patterns::string::AsciiPointer;
//! # use std::ffi::CStr;
//!
//! #[ffi_function]
//! #[no_mangle]
//! pub extern "C" fn print_ascii(x: AsciiPointer) {
//!    // Call `x.as_str()` and handle Result
//! }
//!
//! ```
//!
//! This has the added benefit that any backend supporting a specific pattern will also
//! generate more **idiomatic code in the binding**. In the example above, C# might
//! emit a `ref ubyte` or `IntPtr` type for the `print_ptr`, but will use a correctly marshalled
//! `string` type for `print_ascii`.
//!
//!
//! ## Pattern Backend Support
//!
//! Patterns are exclusively **designed _on top of_ existing, C-compatible functions and types**.
//! That means a backend will handle a pattern in one of three ways:
//!
//! - The pattern is **supported** and the backend will generate the raw, underlying type and / or
//! a language-specific abstraction that safely and conveniently handles it. Examples
//! include converting an [`AsciiPointer`](string) to a C# `string`, or a [`service`](crate::patterns::service)
//! to a Python `class`.
//!
//! - The pattern is not supported and will be **omitted, if the pattern was merely an aggregate** of
//! existing items. Examples include the [`service`](crate::patterns::service) pattern in C which will not
//! be emitted. However, this will not pose a problem as all constituent types and methods (functions)
//! are still available as raw bindings.
//!
//! - The pattern is not supported and will be **replaced with a fallback type**. Examples include
//! the [`AsciiPointer`](string) which will become a regular `*const u8` in C.
//!
//! In other words, regardless of which pattern was used, the involved methods and types will always
//! be accessible from any language.
//!
//! # Status
//!
//! Some patterns have seen more testing (and documentation) than others. The ones
//! marked <sup>🚧</sup> should be considered particularly work-in-progress.

use crate::lang::c::{CType, CompositeType, PrimitiveType};
use crate::patterns::callbacks::NamedCallback;
use crate::patterns::result::FFIErrorEnum;
use crate::patterns::service::Service;

#[doc(hidden)]
pub mod api_entry;
pub mod api_guard;
pub mod callbacks;
pub mod option;
pub mod primitives;
pub mod result;
pub mod service;
pub mod slice;
pub mod string;

/// A pattern on a library level, usually involving both methods and types.
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub enum LibraryPattern {
    Service(Service),
}

/// Used mostly internally and provides pattern info for auto generated structs.
#[doc(hidden)]
pub trait LibraryPatternInfo {
    fn pattern_info() -> LibraryPattern;
}

impl From<Service> for LibraryPattern {
    fn from(x: Service) -> Self {
        Self::Service(x)
    }
}

/// A pattern on a type level.
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub enum TypePattern {
    AsciiPointer,
    APIVersion,
    FFIErrorEnum(FFIErrorEnum),
    Slice(CompositeType),
    SliceMut(CompositeType),
    Option(CompositeType),
    Bool,
    NamedCallback(NamedCallback),
}

impl TypePattern {
    /// For languages like C that don't care about these patterns, give the
    /// C-equivalent fallback type.
    ///
    /// This function will never return a [`CType::Pattern`] variant.
    pub fn fallback_type(&self) -> CType {
        match self {
            TypePattern::AsciiPointer => CType::ReadPointer(Box::new(CType::Primitive(PrimitiveType::U8))),
            TypePattern::FFIErrorEnum(e) => CType::Enum(e.the_enum().clone()),
            TypePattern::Slice(x) => CType::Composite(x.clone()),
            TypePattern::SliceMut(x) => CType::Composite(x.clone()),
            TypePattern::Option(x) => CType::Composite(x.clone()),
            TypePattern::NamedCallback(x) => CType::FnPointer(x.fnpointer().clone()),
            TypePattern::Bool => CType::Primitive(PrimitiveType::U8),
            TypePattern::APIVersion => CType::Primitive(PrimitiveType::U64),
        }
    }
}