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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
// Copyright 2018 foundationdb-rs developers, https://github.com/bluejekyll/foundationdb-rs/graphs/contributors
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! # FoundationDB Rust Client API
//!
//! This is a wrapper library around the FoundationDB (Fdb) C API. It implements futures based interfaces over the Fdb future C implementations.
//!
//! ## Prerequisites
//!
//! ### Install FoundationDB
//!
//! Install FoundationDB on your system, see [FoundationDB Local Development](https://apple.github.io/foundationdb/local-dev.html), or these instructions:
//!
//! - Ubuntu Linux (this may work on the Linux subsystem for Windows as well)
//!
//! ```console
//! $> curl -O https://www.foundationdb.org/downloads/5.1.5/ubuntu/installers/foundationdb-clients_5.1.5-1_amd64.deb
//! $> curl -O https://www.foundationdb.org/downloads/5.1.5/ubuntu/installers/foundationdb-server_5.1.5-1_amd64.deb
//! $> sudo dpkg -i foundationdb-clients_5.1.5-1_amd64.deb
//! $> sudo dpkg -i foundationdb-server_5.1.5-1_amd64.deb
//! ```
//!
//! - macOS
//!
//! ```console
//! $> curl -O https://www.foundationdb.org/downloads/5.1.5/macOS/installers/FoundationDB-5.1.5.pkg
//! $> sudo installer -pkg FoundationDB-5.1.5.pkg -target /
//! ```
//!
//! ## Add dependencies on foundationdb-rs
//!
//! ```toml
//! [dependencies]
//! foundationdb = "*"
//! futures = "0.1"
//! ```
//!
//! ## Extern the crate in `bin.rs` or `lib.rs`
//!
//! ```rust
//! extern crate foundationdb;
//! ```
//!
//! ## Initialization
//!
//! Due to limitations in the C API, the Client and it's associated Network can only be initialized and run once per the life of a process. Generally the `foundationdb::init` function will be enough to initialize the Client. See `foundationdb::default_api` and `foundationdb::builder` for more configuration options of the Fdb Client.
//!
//! ## Example
//!
//! ```rust
//! extern crate futures;
//! extern crate foundationdb;
//!
//! # fn main() {
//!
//! use std::thread;
//! use futures::future::*;
//! use foundationdb::{self, *};
//!
//! let network = foundationdb::init().expect("failed to initialize Fdb client");
//!
//! let handle = std::thread::spawn(move || {
//!     let error = network.run();
//!
//!     if let Err(error) = error {
//!         panic!("fdb_run_network: {}", error);
//!     }
//! });
//!
//! // wait for the network thread to be started
//! network.wait();
//!
//! // work with Fdb
//! let db = Cluster::new(foundationdb::default_config_path())
//!     .and_then(|cluster| cluster.create_database())
//!     .wait().expect("failed to create Cluster");
//!
//! // set a value
//! let trx = db.create_trx().expect("failed to create transaction");
//!
//! trx.set(b"hello", b"world"); // errors will be returned in the future result
//! trx.commit()
//!     .wait()
//!     .expect("failed to set hello to world");
//!
//! // read a value
//! let trx = db.create_trx().expect("failed to create transaction");
//! let result = trx.get(b"hello", false).wait().expect("failed to read world from hello");
//!
//! let value: &[u8] = result.value()
//!     .unwrap();   // unwrap the option
//!
//! // should print "hello world"
//! println!("hello {}", String::from_utf8_lossy(value));
//!
//! // cleanly shutdown the client
//! network.stop().expect("failed to stop Fdb client");
//! handle.join();
//!
//! # }
//! ```
//!
//! ## API stability
//!
//! *WARNING* Until the 1.0 release of this library, the API may be in constant flux.

#![deny(missing_docs)]

#[macro_use]
extern crate failure;
#[macro_use]
extern crate failure_derive;
extern crate byteorder;
extern crate foundationdb_sys;
#[macro_use]
extern crate futures;
#[cfg(feature = "uuid")]
extern crate uuid;

pub mod cluster;
pub mod database;
pub mod error;
pub mod fdb_api;
pub mod future;
pub mod keyselector;
pub mod network;
/// Generated configuration types for use with the various `set_option` functions
#[allow(missing_docs)]
pub mod options;
mod subspace;
pub mod transaction;
pub mod tuple;

//move to prelude?
pub use cluster::Cluster;
pub use database::Database;
pub use error::Error;
pub use subspace::Subspace;
pub use transaction::Transaction;

/// Initialize the FoundationDB Client API, this can only be called once per process.
///
/// # Returns
///
/// `Network` which must be run before the Client is ready. `Network::run` will not return until the
///   network is stopped with the associated `Network::stop` and should be run in a separate thread.
///
/// # Examples
///
/// ```rust
/// use std::thread;
/// use foundationdb;
///
/// let network = foundationdb::init().expect("failed to initialize Fdb");
///
/// let handle = std::thread::spawn(move || {
///     let error = network.run();
///
///     if let Err(error) = error {
///         panic!("fdb_run_network: {}", error);
///     }
/// });
///
/// network.wait();
///
/// // do some interesting things with the API...
///
/// network.stop().expect("failed to stop network");
/// handle.join().expect("failed to join fdb thread");
/// ```
pub fn init() -> error::Result<network::Network> {
    fdb_api::FdbApiBuilder::default().build()?.network().build()
}

/// Initialize the FoundationDB Client API, this can only be called once per process.
///
/// # Returns
///
/// A `NetworkBuilder` which can be used to configure the FoundationDB Client API Network.
///
/// # Example
///
/// ```rust
/// use foundationdb;
/// use foundationdb::options::NetworkOption;
///
/// let network = foundationdb::default_api()
///     .expect("failed to initialize API version")
///     .set_option(NetworkOption::DisableClientStatisticsLogging)
///     .expect("failed to set option")
///     .build()
///     .expect("failed to initialize network");
///
/// // see example on `init`
/// ```
pub fn default_api() -> error::Result<network::NetworkBuilder> {
    Ok(fdb_api::FdbApiBuilder::default().build()?.network())
}

/// Allows the API version, etc, to be configured before starting.
///
/// # Returns
///
/// A `FdbApiBuilder` which can be used to configure the FoundationDB Client API version, etc.
pub fn builder() -> fdb_api::FdbApiBuilder {
    fdb_api::FdbApiBuilder::default()
}

/// Returns the default Fdb cluster configuration file path
#[cfg(target_os = "linux")]
pub fn default_config_path() -> &'static str {
    "/etc/foundationdb/fdb.cluster"
}

/// Returns the default Fdb cluster configuration file path
#[cfg(target_os = "macos")]
pub fn default_config_path() -> &'static str {
    "/usr/local/etc/foundationdb/fdb.cluster"
}

/// Returns the default Fdb cluster configuration file path
#[cfg(target_os = "windows")]
pub fn default_config_path() -> &'static str {
    "C:/ProgramData/foundationdb/fdb.cluster"
}