summaryrefslogtreecommitdiffstats
path: root/ffi/src/core.rs
blob: 3051b13335b382e666bacbadfe9c3429d3b95658 (plain)
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
//! Contexts and errors.
//!
//! Sequoia tries to be useful for a wide variety of applications.
//! Therefore, we need you to provide a little information about the
//! context you are using Sequoia in.
//!
//! # Examples
//!
//! A context with reasonable defaults can be created using
//! `sq_context_new`:
//!
//! ```c
//! #include <sequoia.h>
//!
//! sq_context_t ctx;
//! ctx = sq_context_new (NULL);
//!
//! /* Use Sequoia.  */
//!
//! sq_context_free (ctx);
//! ```
//!
//! A context can be configured using the builder pattern with
//! `sq_context_configure`:
//!
//! ```c
//! #include <sequoia.h>
//!
//! sq_config_t cfg;
//! sq_context_t ctx;
//!
//! cfg = sq_context_configure ();
//! sq_config_network_policy (cfg, SQ_NETWORK_POLICY_OFFLINE);
//! ctx = sq_config_build (cfg, NULL);
//!
//! /* Use Sequoia.  */
//!
//! sq_context_free (ctx);
//! ```

use std::ptr;
use libc::{c_char, c_int};

use sequoia_core as core;
use sequoia_core::Config;

/// Wraps a Context and provides an error slot.
#[doc(hidden)]
pub struct Context {
    pub(crate) c: core::Context,
    e: *mut crate::error::Error,
}

impl Context {
    fn new(c: core::Context) -> Self {
        Context{c: c, e: ptr::null_mut()}
    }

    pub(crate) fn errp(&mut self) -> &mut *mut crate::error::Error {
        &mut self.e
    }
}

/// Returns the last error.
///
/// Returns and removes the last error from the context.
#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
fn sq_context_last_error(ctx: *mut Context) -> *mut crate::error::Error {
    let ctx = ffi_param_ref_mut!(ctx);
    ::std::mem::replace(&mut ctx.e, ptr::null_mut())
}

/// Creates a Context with reasonable defaults.
///
/// Returns `NULL` on errors.  If `errp` is not `NULL`, the error is
/// stored there.
#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
fn sq_context_new(errp: Option<&mut *mut crate::error::Error>)
                  -> *mut Context {
    ffi_make_fry_from_errp!(errp);
    ffi_try_box!(core::Context::new().map(|ctx| Context::new(ctx)))
}

/// Frees a context.
#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
fn sq_context_free(context: Option<&mut Context>) {
    ffi_free!(context)
}

/// Creates a Context that can be configured.
///
/// The configuration is seeded like in `sq_context_new`, but can be
/// modified.  A configuration has to be finalized using
/// `sq_config_build()` in order to turn it into a Context.
#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
fn sq_context_configure() -> *mut Config {
    Box::into_raw(Box::new(core::Context::configure()))
}

/// Returns the directory containing shared state.
#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
fn sq_context_home(ctx: *const Context) -> *const c_char {
    let ctx = ffi_param_ref!(ctx);
    ctx.c.home().to_string_lossy().as_ptr() as *const c_char
}

/// Returns the directory containing backend servers.
#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
fn sq_context_lib(ctx: *const Context) -> *const c_char {
    let ctx = ffi_param_ref!(ctx);
    ctx.c.lib().to_string_lossy().as_bytes().as_ptr() as *const c_char
}

/// Returns the network policy.
#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
fn sq_context_network_policy(ctx: *const Context) -> c_int {
    let ctx = ffi_param_ref!(ctx);
    u8::from(ctx.c.network_policy()) as c_int
}

/// Returns the IPC policy.
#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
fn sq_context_ipc_policy(ctx: *const Context) -> c_int {
    let ctx = ffi_param_ref!(ctx);
    u8::from(ctx.c.ipc_policy()) as c_int
}

/// Returns whether or not this is an ephemeral context.
#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
fn sq_context_ephemeral(ctx: *const Context) -> u8 {
    let ctx = ffi_param_ref!(ctx);
    if ctx.c.ephemeral() { 1 } else { 0 }
}


/*  sequoia::Config.  */

/// Finalizes the configuration and return a `Context`.
///
/// Consumes `cfg`.  Returns `NULL` on errors. Returns `NULL` on
/// errors.  If `errp` is not `NULL`, the error is stored there.
#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
fn sq_config_build(cfg: *mut Config, errp: Option<&mut *mut crate::error::Error>)
                   -> *mut Context {
    ffi_make_fry_from_errp!(errp);
    let cfg = ffi_param_move!(cfg);

    ffi_try_box!(cfg.build().map(|ctx| Context::new(ctx)))
}

/// Sets the directory containing shared state.
#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
fn sq_config_home(cfg: *mut Config, home: *const c_char) {
    let cfg = ffi_param_ref_mut!(cfg);
    let home = ffi_param_cstr!(home).to_string_lossy();
    cfg.set_home(home.as_ref());
}

/// Set the directory containing backend servers.
#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
fn sq_config_lib(cfg: *mut Config, lib: *const c_char) {
    let cfg = ffi_param_ref_mut!(cfg);
    let lib = ffi_param_cstr!(lib).to_string_lossy();
    cfg.set_lib(&lib.as_ref());
}

/// Sets the network policy.
#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
fn sq_config_network_policy(cfg: *mut Config, policy: c_int) {
    let cfg = ffi_param_ref_mut!(cfg);
    if policy < 0 || policy > 3 {
        panic!("Bad network policy: {}", policy);
    }
    cfg.set_network_policy((policy as u8).into());
}

/// Sets the IPC policy.
#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
fn sq_config_ipc_policy(cfg: *mut Config, policy: c_int) {
    let cfg = ffi_param_ref_mut!(cfg);
    if policy < 0 || policy > 2 {
        panic!("Bad ipc policy: {}", policy);
    }
    cfg.set_ipc_policy((policy as u8).into());
}

/// Makes this context ephemeral.
#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
fn sq_config_ephemeral(cfg: *mut Config) {
    let cfg = ffi_param_ref_mut!(cfg);
    cfg.set_ephemeral();
}