1 // Written in the D programming language. 2 /** 3 * Provides access to non-deterministic sources of randomness. These 4 * are implemented as Input Ranges and in many cases are architecture- 5 * or OS-dependent. 6 * 7 * As with the pseudo-random number generators provided elsewhere in 8 * this package, all random devices are implemented as final classes 9 * to ensure reference semantics. 10 * 11 * Warning: This module is currently experimental and should be used 12 * with caution. It is not imported automatically as part of the 13 * hap.random package but must be imported individually in its own 14 * right. Its API may change in future releases. 15 * 16 * Copyright: © 2014 Joseph Rushton Wakeling 17 * 18 * License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 19 * 20 * Authors: $(WEB braingam.es, Joseph Rushton Wakeling) 21 * 22 * Source: $(HAPSRC hap/random/_device.d) 23 */ 24 module hap.random.device; 25 26 import hap.random.traits; 27 28 import std.range, std.traits, std.typetuple; 29 30 /** 31 * $(D TypeTuple) of all random devices defined in this module. 32 * that act as a uniform random number generator. Note that the 33 * available random devices may be dependent on operating system 34 * and/or hardware architecture. 35 */ 36 version (Posix) 37 { 38 pragma(msg, "Module hap.random.device is experimental. Use with caution."); 39 alias UniformRandomDeviceTypes = 40 TypeTuple!(DevRandom!ushort, DevRandom!uint, DevRandom!ulong, 41 DevURandom!ushort, DevURandom!uint, DevURandom!ulong); 42 } 43 else 44 { 45 pragma(msg, "Module hap.random.device is not currently supported on your operating system."); 46 alias UniformRandomDeviceTypes = 47 TypeTuple!(); 48 } 49 50 unittest 51 { 52 foreach (Dev; UniformRandomDeviceTypes) 53 { 54 static assert (isUniformRNG!Dev); 55 56 auto rnd = new Dev; 57 58 auto init = rnd.front; 59 size_t i = 50; 60 do 61 { 62 rnd.popFront(); 63 } 64 while (--i && rnd.front == init); 65 66 assert(i > 0); 67 assert(i < 50); 68 } 69 } 70 71 /** 72 * Reads randomness from an infinite filestream. In practice this 73 * will typically be used to read from system sources of randomness 74 * such as (on Posix) $(D /dev/random) or $(D /dev/urandom). 75 * 76 * The random numbers generated will be unsigned integers of type 77 * $(D T) in the range [$(D T.min), $(D T.max)]. A good source of 78 * randomness should ensure these are uniformly distributed. 79 * 80 * It is the responsibility of the user to ensure that the specified 81 * source of randomness indeed contains sufficient data to serve the 82 * requirements of their program. 83 */ 84 final class RandomFileStream(string filename, T) 85 if (isIntegral!T && isUnsigned!T) 86 { 87 private: 88 import std.stdio; 89 File _dev; 90 T _value; 91 92 public: 93 alias source = filename; 94 enum T min = T.min; 95 enum T max = T.max; 96 97 enum bool isUniformRandom = true; 98 99 static assert (this.min == 0); 100 101 this() 102 { 103 _dev = File(filename, "r"); 104 popFront(); 105 } 106 107 /// Range primitives 108 enum bool empty = false; 109 110 /// ditto 111 T front() @property @safe const nothrow pure 112 { 113 return _value; 114 } 115 116 /// ditto 117 void popFront() 118 { 119 _dev.rawRead((&_value)[0 .. 1]); 120 } 121 } 122 123 version (Posix) 124 { 125 /** 126 * Generates uniformly distributed random numbers in the interval 127 * [$(D T.min), $(D T.max)] using $(D /dev/random) as the source 128 * of randomness. 129 * 130 * Caution should be taken when using this as $(D /dev/random) is 131 * a blocking device. 132 */ 133 template DevRandom(T) 134 if (isIntegral!T && isUnsigned!T) 135 { 136 alias DevRandom = RandomFileStream!("/dev/random", T); 137 } 138 139 /** 140 * Generates uniformly distributed random numbers in the interval 141 * [$(D T.min), $(D T.max)] using $(D /dev/urandom) as the source 142 * of randomness. 143 */ 144 template DevURandom(T) 145 if (isIntegral!T && isUnsigned!T) 146 { 147 alias DevURandom = RandomFileStream!("/dev/urandom", T); 148 } 149 }