randomorg/lib.rs
1//! A random.org api bindings.
2//!
3//! The randomness comes from atmospheric noise, which for many purposes is better than the
4//! pseudo-random number algorithms typically used in computer programs. To use the library you
5//! must have an api key which you may get [from here](https://api.random.org/api-keys/beta).
6//!
7//! # Usage
8//!
9//! ```rust,no_run
10//! extern crate randomorg;
11//!
12//! fn main() {
13//! use randomorg::Random;
14//! let r = Random::new("API KEY HERE");
15//! println!("Result: {:?}", r.generate_integers(-100, 100, 15, true));
16//! let random_data = r.request_integers().min(0).max(100).limit(5).collect::<Vec<i32>>();
17//! println!("Random integers: {:?}", random_data);
18//! }
19//! ```
20//!
21//! # Warning
22//!
23//! However the library provides a thread-safe object, the **random.org** service does not allow
24//! to use their API from multithreaded-apps. The service processes incoming calls according the
25//! `request_id` parameter, it must be different for concurrent calls, while this library always
26//! provides `request_id` equal to `1`. So when you use the library from multiple threads the
27//! library will send multiple requests simultaneously with the same `request_id` field and the
28//! **random.org** service will refuse to process them.
29
30#![deny(clippy::all)]
31#![deny(clippy::pedantic)]
32#![deny(missing_docs)]
33#![deny(warnings)]
34
35mod date_de;
36mod error;
37mod methods;
38mod model;
39mod params;
40#[cfg(feature = "rng")]
41pub mod rand;
42mod request_builders;
43mod requests;
44mod results;
45pub mod version;
46
47use methods::Method;
48pub use model::{AllowedCharacters, ApiKey, ApiKeyStatus, Request, RequestId, Response};
49pub use request_builders::{
50 RequestBlobs, RequestDecimalFractions, RequestGaussians, RequestIntegers, RequestStrings,
51 RequestUUIDs,
52};
53use requests::{
54 EmptyRequest, GenerateBlobsRequest, GenerateDecimalFractionsRequest, GenerateGaussiansRequest,
55 GenerateIntegersRequest, GenerateStringsRequest, GenerateUUIDsRequest,
56};
57pub use results::{
58 GenerateBlobsResult, GenerateDecimalFractionsResult, GenerateGaussiansResult,
59 GenerateIntegersResult, GenerateStringsResult, GenerateUUIDsResult, GetUsageResult, RandomData,
60 RandomResult,
61};
62
63pub use error::{Error, ErrorCode, ResponseError, Result};
64
65const API_INVOKE: &str = "https://api.random.org/json-rpc/2/invoke";
66
67/// Macro only for internal use with the `Random` object (relies on its fields).
68/// Performs a request.
69macro_rules! make_request {
70 ($api:ident, $body:expr) => {{
71 $api.client.post(API_INVOKE).json($body).send()
72 }};
73}
74
75/// Macro only for internal use with the `Random` object (relies on it's fields)
76/// Parses a service data from the request's response.
77macro_rules! request {
78 ($api:ident, $request:ident) => {
79 Ok(make_request!($api, &$request)?.json()?)
80 };
81}
82
83/// A random.org api client.
84#[derive(Debug, Clone)]
85pub struct Random {
86 client: reqwest::blocking::Client,
87 api_key: ApiKey,
88}
89
90impl Random {
91 /// Creates new random.org client.
92 ///
93 /// # Usage
94 ///
95 /// ```rust
96 /// extern crate randomorg;
97 ///
98 /// fn main() {
99 /// use randomorg::Random;
100 /// let r = Random::new("API KEY HERE");
101 /// }
102 /// ```
103 pub fn new<S: Into<String>>(api_key: S) -> Random {
104 Random {
105 client: reqwest::blocking::Client::new(),
106 api_key: ApiKey(api_key.into()),
107 }
108 }
109
110 /// Create a request object for generating random integers
111 ///
112 /// # Usage
113 ///
114 /// ```rust,no_run
115 /// extern crate randomorg;
116 ///
117 /// fn main() {
118 /// use randomorg::Random;
119 /// let r = Random::new("API KEY HERE");
120 /// let random_data = r.request_integers().min(0).max(100).limit(5).collect::<Vec<i32>>();
121 /// println!("Random integers: {:?}", random_data);
122 /// }
123 /// ```
124 pub fn request_integers(&self) -> RequestIntegers {
125 RequestIntegers::new(self)
126 }
127
128 /// Create a request object for generating random decimal fractions
129 ///
130 /// # Usage
131 ///
132 /// ```rust,no_run
133 /// extern crate randomorg;
134 ///
135 /// fn main() {
136 /// use randomorg::Random;
137 /// let r = Random::new("API KEY HERE");
138 /// let random_data = r.request_decimal_fractions().limit(5)
139 /// .decimal_places(4)
140 /// .collect::<Vec<f32>>();
141 /// println!("Random decimal fractions: {:?}", random_data);
142 /// }
143 /// ```
144 pub fn request_decimal_fractions(&self) -> RequestDecimalFractions {
145 RequestDecimalFractions::new(self)
146 }
147
148 /// Create a request object for generating random gaussians
149 ///
150 /// # Usage
151 ///
152 /// ```rust,no_run
153 /// extern crate randomorg;
154 ///
155 /// fn main() {
156 /// use randomorg::Random;
157 /// let r = Random::new("API KEY HERE");
158 /// let random_data = r.request_gaussians().limit(5)
159 /// .collect::<Vec<f32>>();
160 /// println!("Random gaussians: {:?}", random_data);
161 /// }
162 /// ```
163 pub fn request_gaussians(&self) -> RequestGaussians {
164 RequestGaussians::new(self)
165 }
166
167 /// Create a request object for generating random strings
168 ///
169 /// # Usage
170 ///
171 /// ```rust,no_run
172 /// extern crate randomorg;
173 ///
174 /// fn main() {
175 /// use randomorg::Random;
176 /// let r = Random::new("API KEY HERE");
177 /// let random_data = r.request_strings().limit(5)
178 /// .collect::<Vec<String>>();
179 /// println!("Random strings: {:?}", random_data);
180 /// }
181 /// ```
182 pub fn request_strings(&self) -> RequestStrings {
183 RequestStrings::new(self)
184 }
185
186 /// Create a request object for generating random UUIDs
187 ///
188 /// # Usage
189 ///
190 /// ```rust,no_run
191 /// extern crate randomorg;
192 ///
193 /// fn main() {
194 /// use randomorg::Random;
195 /// let r = Random::new("API KEY HERE");
196 /// let random_data = r.request_uuids().limit(5)
197 /// .collect::<Vec<String>>();
198 /// println!("Random strings: {:?}", random_data);
199 /// }
200 /// ```
201 pub fn request_uuids(&self) -> RequestUUIDs {
202 RequestUUIDs::new(self)
203 }
204
205 /// Create a request object for generating random blobs
206 ///
207 /// # Usage
208 ///
209 /// ```rust,no_run
210 /// extern crate randomorg;
211 ///
212 /// fn main() {
213 /// use randomorg::Random;
214 /// let r = Random::new("API KEY HERE");
215 /// let random_data = r.request_blobs().limit(5)
216 /// .collect::<Vec<String>>();
217 /// println!("Random strings: {:?}", random_data);
218 /// }
219 /// ```
220 pub fn request_blobs(&self) -> RequestBlobs {
221 RequestBlobs::new(self)
222 }
223
224 /// This method generates true random integers within a user-defined range.
225 ///
226 /// * [Official documentation](https://api.random.org/json-rpc/2/basic#generateIntegers)
227 ///
228 /// # Usage
229 ///
230 /// ```rust,no_run
231 /// extern crate randomorg;
232 ///
233 /// fn main() {
234 /// use randomorg::Random;
235 /// let r = Random::new("API KEY HERE");
236 /// println!("Result: {:?}", r.generate_integers(-100, 100, 15, true));
237 /// }
238 /// ```
239 ///
240 /// # Constraints
241 /// * `min` must be within [-1e9; 1e9] range
242 /// * `max` must be within [-1e9; 1e9] range
243 /// * `limit` must be within [1; 1e4] range
244 pub fn generate_integers(
245 &self,
246 min: i32,
247 max: i32,
248 limit: u16,
249 replacement: bool,
250 ) -> Result<Response<GenerateIntegersResult>> {
251 let request =
252 GenerateIntegersRequest::new(self.api_key.clone(), min, max, limit, replacement);
253 request!(self, request)
254 }
255
256 /// This method generates true random decimal fractions from a uniform distribution across
257 /// the [0,1] interval with a user-defined number of decimal places.
258 ///
259 /// * [Official documentation](https://api.random.org/json-rpc/2/basic#generateDecimalFractions)
260 ///
261 /// # Usage
262 ///
263 /// ```rust,no_run
264 /// extern crate randomorg;
265 ///
266 /// fn main() {
267 /// use randomorg::Random;
268 /// let r = Random::new("API KEY HERE");
269 /// println!("Result: {:?}", r.generate_decimal_fractions(10, 8));
270 /// }
271 /// ```
272 ///
273 /// # Constraints
274 /// * `limit` must be within [1; 1e4] range
275 /// * `decimal_places` must be within [1; 20] range
276 pub fn generate_decimal_fractions(
277 &self,
278 limit: u16,
279 decimal_places: u8,
280 ) -> Result<Response<GenerateDecimalFractionsResult>> {
281 let request =
282 GenerateDecimalFractionsRequest::new(self.api_key.clone(), limit, decimal_places);
283 request!(self, request)
284 }
285
286 /// This method generates true random numbers from a Gaussian distribution (also known as a
287 /// normal distribution). The form uses a Box-Muller Transform to generate the Gaussian
288 /// distribution from uniformly distributed numbers.
289 ///
290 /// * [Official documentation](https://api.random.org/json-rpc/2/basic#generateGaussians)
291 ///
292 /// # Usage
293 ///
294 /// ```rust,no_run
295 /// extern crate randomorg;
296 ///
297 /// fn main() {
298 /// use randomorg::Random;
299 /// let r = Random::new("API KEY HERE");
300 /// println!("Result: {:?}", r.generate_gaussians(2000, 1100, 100, 4));
301 /// }
302 /// ```
303 ///
304 /// # Constraints
305 /// * `limit` must be within [1; 1e4] range
306 /// * `mean` must be within [-1e6; 1e6] range
307 /// * `standard_deviation` must be within [-1e6; 1e6] range
308 /// * `significant_digits` must be within [2; 20] range
309 pub fn generate_gaussians(
310 &self,
311 limit: u16,
312 mean: i32,
313 standard_deviation: i32,
314 significant_digits: u8,
315 ) -> Result<Response<GenerateGaussiansResult>> {
316 let request = GenerateGaussiansRequest::new(
317 self.api_key.clone(),
318 limit,
319 mean,
320 standard_deviation,
321 significant_digits,
322 );
323 request!(self, request)
324 }
325
326 /// This method generates true random strings.
327 ///
328 /// * [Official documentation](https://api.random.org/json-rpc/2/basic#generateStrings)
329 ///
330 /// # Usage
331 ///
332 /// ```rust,no_run
333 /// extern crate randomorg;
334 ///
335 /// fn main() {
336 /// use randomorg::{ Random, AllowedCharacters };
337 /// use std::collections::BTreeSet;
338 /// let chars = "abcde".chars().collect::<BTreeSet<char>>();
339 /// let r = Random::new("API KEY HERE");
340 /// println!("Result: {:?}", r.generate_strings(5, 10, AllowedCharacters(chars)));
341 /// }
342 /// ```
343 ///
344 /// # Constraints
345 /// * `limit` must be within [1; 1e4] range
346 /// * `length` must be within [1; 20] range
347 /// * `characters` must contain maximum 80 characters.
348 pub fn generate_strings(
349 &self,
350 limit: u16,
351 length: u8,
352 characters: AllowedCharacters,
353 ) -> Result<Response<GenerateStringsResult>> {
354 let request = GenerateStringsRequest::new(self.api_key.clone(), limit, length, characters);
355 request!(self, request)
356 }
357
358 /// This method generates version 4 true random Universally Unique IDentifiers (UUIDs) in
359 /// accordance with section 4.4 of RFC 4122.
360 ///
361 /// * [Official documentation](https://api.random.org/json-rpc/2/basic#generateUUIDs)
362 ///
363 /// # Usage
364 ///
365 /// ```rust,no_run
366 /// extern crate randomorg;
367 ///
368 /// fn main() {
369 /// use randomorg::Random;
370 /// let r = Random::new("API KEY HERE");
371 /// println!("Result: {:?}", r.generate_uuids(5));
372 /// }
373 /// ```
374 ///
375 /// # Constraints
376 /// * `limit` must be within [1; 1e3] range
377 pub fn generate_uuids(&self, limit: u16) -> Result<Response<GenerateUUIDsResult>> {
378 let request = GenerateUUIDsRequest::new(self.api_key.clone(), limit);
379 request!(self, request)
380 }
381
382 /// This method generates Binary Large OBjects (BLOBs) containing true random data.
383 ///
384 /// * [Official documentation](https://api.random.org/json-rpc/2/basic#generateBlobs)
385 ///
386 /// # Usage
387 ///
388 /// ```rust,no_run
389 /// extern crate randomorg;
390 ///
391 /// fn main() {
392 /// use randomorg::Random;
393 /// let r = Random::new("API KEY HERE");
394 /// println!("Result: {:?}", r.generate_blobs(5, 16));
395 /// }
396 /// ```
397 ///
398 /// # Constraints
399 /// * `limit` must be within [1; 100] range
400 /// * `size` must be within [1, 1048576] range
401 pub fn generate_blobs(&self, limit: u16, size: u32) -> Result<Response<GenerateBlobsResult>> {
402 let request = GenerateBlobsRequest::new(self.api_key.clone(), limit, size);
403 request!(self, request)
404 }
405
406 /// Returns information related to the usage of a given API key.
407 ///
408 /// * [Official documentation](https://api.random.org/json-rpc/2/basic#getUsage)
409 ///
410 /// # Usage
411 ///
412 /// ```rust,no_run
413 /// extern crate randomorg;
414 ///
415 /// fn main() {
416 /// use randomorg::Random;
417 /// let r = Random::new("API KEY HERE");
418 /// println!("Result: {:?}", r.get_usage());
419 /// }
420 /// ```
421 pub fn get_usage(&self) -> Result<Response<GetUsageResult>> {
422 let request = EmptyRequest::new(Method::GetUsage, self.api_key.clone());
423 request!(self, request)
424 }
425}
426
427#[cfg(test)]
428mod tests {
429 fn assert_sync_and_send<T: Sync + Send>() {}
430
431 #[test]
432 fn test_sync_and_send() {
433 assert_sync_and_send::<crate::Random>();
434 }
435}