Skip to main content

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}