fart/
lib.rs

1//! # `fart`: **f**itzgen's generative **art**
2//!
3//! ## Example
4//!
5//! Drawing a random triangle!
6//!
7//! ```no_run
8//! use fart::prelude::*;
9//!
10//! fn main() {
11//!     fart::generate(|cfg| {
12//!         let mut canvas = Canvas::new(Aabb::new(
13//!             point2(0, 0),
14//!             point2(1000, 1000),
15//!         ));
16//!
17//!         let x_dist = Uniform::new(0, 1000);
18//!         let y_dist = Uniform::new(0, 1000);
19//!
20//!         let triangle = fart::geom::Polygon::new(vec![
21//!             point2(x_dist.sample(cfg.rng()), y_dist.sample(cfg.rng())),
22//!             point2(x_dist.sample(cfg.rng()), y_dist.sample(cfg.rng())),
23//!             point2(x_dist.sample(cfg.rng()), y_dist.sample(cfg.rng())),
24//!         ]);
25//!
26//!         canvas.draw(&triangle);
27//!
28//!         Ok(canvas.create_svg(Millis(200.0), Millis(200.0)))
29//!     });
30//! }
31//! ```
32
33#![deny(missing_docs, missing_debug_implementations)]
34
35pub mod canvas;
36pub mod path;
37pub mod prelude;
38pub mod process;
39
40mod thread_rng;
41mod user_const;
42
43// Re-exports of our public dependencies.
44pub use euclid;
45pub use failure;
46pub use fart_2d_geom as geom;
47pub use fart_aabb as aabb;
48pub use lazy_static;
49pub use noise;
50pub use num_traits;
51pub use rand;
52pub use svg;
53
54pub use thread_rng::FartThreadRng;
55
56use failure::ResultExt;
57use std::env;
58use std::path::PathBuf;
59
60/// Either an `Ok(T)` or an `Err(failure::Error)`.
61pub type Result<T> = ::std::result::Result<T, failure::Error>;
62
63/// Configuration options for SVG generation.
64#[derive(Debug)]
65pub struct Config {
66    file_name: PathBuf,
67    rng: FartThreadRng,
68}
69
70impl Config {
71    fn new() -> Result<Config> {
72        let file_name =
73            env::var("FART_FILE_NAME").context("missing required FART_FILE_NAME env var")?;
74        let file_name = PathBuf::from(file_name);
75
76        let rng = rng();
77
78        Ok(Config { file_name, rng })
79    }
80
81    /// Get a random number generator.
82    ///
83    /// Deprecated. Use `fart::rng()` instead.
84    #[inline]
85    #[deprecated(note = "Use `fart::rng()` instead.")]
86    pub fn rng(&mut self) -> &mut impl rand::Rng {
87        &mut self.rng
88    }
89}
90
91/// Generate an SVG with the given function `f`.
92///
93/// ```no_run
94/// # #![allow(warnings)]
95/// fn main() {
96///     fart::generate(|cfg| {
97///         unimplemented!("Your code here...")
98///     });
99/// }
100/// ```
101pub fn generate<F>(f: F) -> !
102where
103    F: FnOnce(&mut Config) -> Result<svg::Document>,
104{
105    let then = std::time::Instant::now();
106    let code = match try_generate(f) {
107        Ok(()) => {
108            eprintln!(
109                "Generated in {:?}",
110                std::time::Instant::now().duration_since(then)
111            );
112            0
113        }
114        Err(e) => {
115            eprintln!("Error: {}", e);
116            for c in e.iter_causes() {
117                eprintln!("    Caused by: {}", c);
118            }
119            1
120        }
121    };
122    std::process::exit(code);
123}
124
125fn try_generate<F>(f: F) -> Result<()>
126where
127    F: FnOnce(&mut Config) -> Result<svg::Document>,
128{
129    let mut config = Config::new().context("failed to read configuration")?;
130    let doc = f(&mut config).context("function supplied to `fart::generate` failed")?;
131    svg::save(&config.file_name, &doc).context("failed to save SVG to a file")?;
132    Ok(())
133}
134
135/// Get this thread's `FartThreadRng`!
136pub fn rng() -> FartThreadRng {
137    return FartThreadRng::default();
138}