1 /++ 2 This module only contains a template mixin used to generate 3 SI units, prefixes and utility functions usable at run time. 4 5 Copyright: Copyright 2013-2018, Nicolas Sicard 6 Authors: Nicolas Sicard 7 License: $(LINK www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 8 Source: $(LINK https://github.com/biozic/quantities) 9 +/ 10 module quantities.runtime.si.definitions; 11 12 /++ 13 Generates SI units, prefixes and several utility functions 14 (parsing and formatting) usable at run time. 15 +/ 16 mixin template RuntimeSI(N) 17 { 18 import std.traits : isSomeString; 19 20 /// A list of common SI symbols and prefixes 21 static __gshared SymbolList!N siSymbols; 22 shared static this() 23 { 24 siSymbols = siSymbolList; 25 } 26 27 import quantities.runtime.qvariant; 28 import std.traits : isSomeString; 29 30 /++ 31 Parses a string for a quantity of type Q at run time. 32 33 Throws a DimensionException. 34 35 Params: 36 str = the string to parse. 37 +/ 38 QVariant!N parseSI(S)(S str) 39 if (isSomeString!S) 40 { 41 import quantities.runtime.parsing : Parser; 42 import std.conv : parse; 43 44 static Parser!(N, (ref S s) => parse!N(s)) siParser; 45 static bool initialized = false; 46 if (!initialized) 47 siParser.symbolList = siSymbols; 48 return siParser.parse(str); 49 } 50 /// 51 unittest 52 { 53 auto t = parseSI("90 min"); 54 assert(t == 90 * minute); 55 t = parseSI("h"); 56 assert(t == 1 * hour); 57 58 auto v = parseSI("2"); 59 assert(v == (2 * meter) / meter); 60 } 61 62 /++ 63 Format a SI quantity according to a format string known at run time. 64 65 Params: 66 format = The format string. Must start with a format specification 67 for the value of the quantity (a numeric type), that must be 68 followed by the symbol of a SI unit. 69 quantity = The quantity that must be formatted. 70 +/ 71 SIFormatter siFormat(string format, QVariant!N quantity) 72 { 73 return SIFormatter(format, quantity); 74 } 75 /// 76 unittest 77 { 78 import std.conv : text; 79 80 QVariant!double speed = 12.5 * kilo(meter) / hour; 81 assert(siFormat("%.2f m/s", speed).text == "3.47 m/s"); 82 } 83 84 /// Ditto 85 struct SIFormatter 86 { 87 private 88 { 89 string fmt; 90 QVariant!N unit; 91 QVariant!N quantity; 92 } 93 94 /++ 95 Create a formatter struct. 96 97 Params: 98 format = The format string. Must start with a format specification 99 for the value of the quantity (a numeric type), that must be 100 followed by the symbol of a SI unit. 101 quantity = The quantity that must be formatted. 102 +/ 103 this(string format, QVariant!N quantity) 104 { 105 import std.format : FormatSpec; 106 import std.array : Appender; 107 108 fmt = format; 109 auto spec = FormatSpec!char(format); 110 auto app = Appender!string(); 111 spec.writeUpToNextSpec(app); 112 unit = parseSI(spec.trailing); 113 this.quantity = quantity; 114 } 115 116 /// 117 void toString(scope void delegate(const(char)[]) sink) const 118 { 119 import std.format : formattedWrite; 120 121 sink.formattedWrite(fmt, quantity.value(unit)); 122 } 123 } 124 }