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
//! Utility / conveniece functions for commonly use graphical shapes

use scale::Pt;
use Point;

// PDF doesn't understand what a "circle" is, so we have to
// approximate it.
const C: f64 = 0.551915024494;

/// Calculates and returns the points for an approximated circle, given a radius and an
/// offset into the page from the lower left corner.
#[inline]
pub fn calculate_points_for_circle<P: Into<Pt>>(
    radius: P,
    offset_x: P,
    offset_y: P,
) -> Vec<(Point, bool)> {
    let (radius, offset_x, offset_y) = (radius.into(), offset_x.into(), offset_y.into());
    let radius = radius.0;

    let p10 = Point { x: Pt(0.0 * radius), y: Pt(1.0 * radius) };
    let p11 = Point { x: Pt(C   * radius), y: Pt(1.0 * radius) };
    let p12 = Point { x: Pt(1.0 * radius), y: Pt(C   * radius) };
    let p13 = Point { x: Pt(1.0 * radius), y: Pt(0.0 * radius) };

    let p20 = Point { x: Pt(1.0 * radius), y: Pt(0.0 * radius) };
    let p21 = Point { x: Pt(1.0 * radius), y: Pt(-C  * radius) };
    let p22 = Point { x: Pt(C   * radius), y: Pt(-1.0 * radius) };
    let p23 = Point { x: Pt(0.0 * radius), y: Pt(-1.0 * radius) };

    let p30 = Point { x: Pt(0.0 * radius),  y: Pt(-1.0 * radius) };
    let p31 = Point { x: Pt(-C  * radius),  y: Pt(-1.0 * radius) };
    let p32 = Point { x: Pt(-1.0 * radius), y: Pt(-C   * radius) };
    let p33 = Point { x: Pt(-1.0 * radius), y: Pt(0.0 * radius) };

    let p40 = Point { x: Pt(-1.0 * radius), y: Pt(0.0 * radius) };
    let p41 = Point { x: Pt(-1.0 * radius), y: Pt(C * radius) };
    let p42 = Point { x: Pt(-C * radius),   y: Pt(1.0  * radius) };
    let p43 = Point { x: Pt(0.0 * radius),  y: Pt(1.0 * radius) };

    let mut pts  = vec![(p10, true), (p11, true), (p12, true), (p13, false),
                        (p20, true), (p21, true), (p22, true), (p23, false),
                        (p30, true), (p31, true), (p32, true), (p33, false),
                        (p40, true), (p41, true), (p42, true), (p43, false),
    ];

    for &mut (ref mut p, _) in pts.iter_mut() {
        p.x.0 += offset_x.0;
        p.y.0 += offset_y.0;
    }

    pts
}

/// Calculates and returns the points for a rectangle, given a horizontal and vertical scale,
/// and an offset into the page from the lower left corner.
#[inline]
pub fn calculate_points_for_rect<P: Into<Pt>>(
    scale_x: P,
    scale_y: P,
    offset_x: P,
    offset_y: P,
) -> Vec<(Point, bool)> {
    let (scale_x, scale_y, offset_x, offset_y) = (
        scale_x.into(),
        scale_y.into(),
        offset_x.into(),
        offset_y.into(),
    );
    let top = Pt(offset_y.0 + (scale_y.0 / 2.0));
    let bottom = Pt(offset_y.0 - (scale_y.0 / 2.0));
    let left = Pt(offset_x.0 - (scale_x.0 / 2.0));
    let right = Pt(offset_x.0 + (scale_x.0 / 2.0));

    let top_left_pt = Point { x: left, y: top };
    let top_right_pt = Point { x: right, y: top };
    let bottom_right_pt = Point { x: right, y: bottom };
    let bottom_left_pt = Point { x: left, y: bottom };

    vec![(top_left_pt, false), (top_right_pt, false), (bottom_right_pt, false), (bottom_left_pt, false)]
}

use std::sync::atomic::{AtomicUsize, Ordering};

/// Since the random number generator doesn't have to be cryptographically secure
/// it doesn't make sense to import the entire rand library, so this is just a
/// xorshift pseudo-random function
static RAND_SEED: AtomicUsize = AtomicUsize::new(2100);

/// Xorshift-based random number generator. Impure function
pub(crate) fn rand() -> usize {
    let mut x = RAND_SEED.fetch_add(21, Ordering::SeqCst);
    #[cfg(target_pointer_width = "64")] {
        x ^= x << 21;
        x ^= x >> 35;
        x ^= x << 4;
        x
    }

    #[cfg(target_pointer_width = "32")] {
        x ^= x << 13;
        x ^= x >> 17;
        x ^= x << 5;
        x
    }
}

/// Returns a string with 32 random characters
pub(crate) fn random_character_string_32() -> String {

    const MAX_CHARS: usize = 32;
    let mut final_string = String::with_capacity(MAX_CHARS);
    let mut char_pos = 0;

    'outer: while char_pos < MAX_CHARS {
        let rand = format!("{}", rand());
        for ch in rand.chars() {
            if char_pos < MAX_CHARS {
                final_string.push(u8_to_char(ch.to_digit(10).unwrap() as u8));
                char_pos += 1;
            } else {
                break 'outer;
            }
        }
    }

    final_string
}

#[inline(always)]
fn u8_to_char(input: u8) -> char {
    ('A' as u8 + input) as char
}