mirror of https://github.com/buggins/dlangui.git
settings refactoring
This commit is contained in:
parent
199b0ef2a2
commit
dcd5b33b2c
|
@ -4,6 +4,391 @@ import std.range;
|
||||||
import std.algorithm;
|
import std.algorithm;
|
||||||
import std.conv;
|
import std.conv;
|
||||||
|
|
||||||
|
enum SettingType {
|
||||||
|
STRING,
|
||||||
|
INTEGER,
|
||||||
|
UINTEGER,
|
||||||
|
FLOAT,
|
||||||
|
OBJECT,
|
||||||
|
ARRAY,
|
||||||
|
TRUE,
|
||||||
|
FALSE,
|
||||||
|
NULL
|
||||||
|
}
|
||||||
|
|
||||||
|
/// array
|
||||||
|
struct SettingArray {
|
||||||
|
Setting[] list;
|
||||||
|
@property bool empty() inout { return list.length == 0; }
|
||||||
|
Setting set(int index, Setting value, Setting parent = null) {
|
||||||
|
if (index < 0)
|
||||||
|
index = cast(int)(list.length);
|
||||||
|
if (index >= list.length) {
|
||||||
|
int oldlen = cast(int)list.length;
|
||||||
|
list.length = index + 1;
|
||||||
|
for (int i = oldlen; i < index; i++)
|
||||||
|
list[i] = new Setting(); // insert NULL items in holes
|
||||||
|
}
|
||||||
|
list[index] = value;
|
||||||
|
value.parent = parent;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
/// get item by index, returns null if index out of bounds
|
||||||
|
Setting get(int index) {
|
||||||
|
if (index < 0 || index >= list.length)
|
||||||
|
return null;
|
||||||
|
return list[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ordered map
|
||||||
|
struct SettingMap {
|
||||||
|
Setting[] list;
|
||||||
|
int[string] map;
|
||||||
|
@property bool empty() inout { return list.length == 0; }
|
||||||
|
/// get item by index, returns null if index out of bounds
|
||||||
|
Setting get(int index) {
|
||||||
|
if (index < 0 || index >= list.length)
|
||||||
|
return null;
|
||||||
|
return list[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// setting object
|
||||||
|
final class Setting {
|
||||||
|
union Store {
|
||||||
|
string str;
|
||||||
|
long integer;
|
||||||
|
ulong uinteger;
|
||||||
|
double floating;
|
||||||
|
SettingArray array;
|
||||||
|
SettingMap * map;
|
||||||
|
}
|
||||||
|
private Setting _parent;
|
||||||
|
private Store _store;
|
||||||
|
private SettingType _type = SettingType.NULL;
|
||||||
|
|
||||||
|
this() {
|
||||||
|
// NULL setting
|
||||||
|
}
|
||||||
|
this(long v) {
|
||||||
|
integer = v;
|
||||||
|
}
|
||||||
|
this(ulong v) {
|
||||||
|
uinteger = v;
|
||||||
|
}
|
||||||
|
this(string v) {
|
||||||
|
str = v;
|
||||||
|
}
|
||||||
|
this(double v) {
|
||||||
|
floating = v;
|
||||||
|
}
|
||||||
|
this(bool v) {
|
||||||
|
boolean = v;
|
||||||
|
}
|
||||||
|
this(Setting[] v) {
|
||||||
|
clear(SettingType.ARRAY);
|
||||||
|
_store.array.list = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get parent
|
||||||
|
@property inout(Setting) parent() inout { return _parent; }
|
||||||
|
/// set parent
|
||||||
|
@property Setting parent(Setting v) {
|
||||||
|
_parent = v;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property SettingType type() const { return _type; }
|
||||||
|
/// clear value and set new type
|
||||||
|
void clear(SettingType newType) {
|
||||||
|
if (newType != _type) {
|
||||||
|
clear();
|
||||||
|
_type = newType;
|
||||||
|
}
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
/// clear value
|
||||||
|
void clear() {
|
||||||
|
final switch(_type) with(SettingType) {
|
||||||
|
case STRING:
|
||||||
|
_store.str = null;
|
||||||
|
break;
|
||||||
|
case ARRAY:
|
||||||
|
_store.array = _store.array.init;
|
||||||
|
break;
|
||||||
|
case OBJECT:
|
||||||
|
_store.map = _store.map.init;
|
||||||
|
break;
|
||||||
|
case INTEGER:
|
||||||
|
_store.integer = _store.integer.init;
|
||||||
|
break;
|
||||||
|
case UINTEGER:
|
||||||
|
_store.uinteger = _store.uinteger.init;
|
||||||
|
break;
|
||||||
|
case FLOAT:
|
||||||
|
_store.floating = _store.floating.init;
|
||||||
|
break;
|
||||||
|
case TRUE:
|
||||||
|
case FALSE:
|
||||||
|
case NULL:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// read as string value
|
||||||
|
@property inout(string) str() inout {
|
||||||
|
final switch(_type) with(SettingType) {
|
||||||
|
case STRING:
|
||||||
|
return _store.str;
|
||||||
|
case INTEGER:
|
||||||
|
return to!string(_store.integer);
|
||||||
|
case UINTEGER:
|
||||||
|
return to!string(_store.uinteger);
|
||||||
|
case FLOAT:
|
||||||
|
return to!string(_store.floating);
|
||||||
|
case TRUE:
|
||||||
|
return "true";
|
||||||
|
case FALSE:
|
||||||
|
return "false";
|
||||||
|
case NULL:
|
||||||
|
case ARRAY:
|
||||||
|
case OBJECT:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// set string value for object
|
||||||
|
@property string str(string v) {
|
||||||
|
if (_type != SettingType.STRING)
|
||||||
|
clear(SettingType.STRING);
|
||||||
|
_store.str = v;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long parseLong(inout string v, long defValue = 0) {
|
||||||
|
int len = cast(int)v.length;
|
||||||
|
if (len == 0)
|
||||||
|
return defValue;
|
||||||
|
int sign = 1;
|
||||||
|
long value = 0;
|
||||||
|
int digits = 0;
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
char ch = v[i];
|
||||||
|
if (ch == '-') {
|
||||||
|
if (i != 0)
|
||||||
|
return defValue;
|
||||||
|
sign = -1;
|
||||||
|
} else if (ch >= '0' && ch <= '9') {
|
||||||
|
digits++;
|
||||||
|
value = value * 10 + (ch - '0');
|
||||||
|
} else {
|
||||||
|
return defValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return digits > 0 ? (sign > 0 ? value : -value) : defValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ulong parseULong(inout string v, ulong defValue = 0) {
|
||||||
|
int len = cast(int)v.length;
|
||||||
|
if (len == 0)
|
||||||
|
return defValue;
|
||||||
|
ulong value = 0;
|
||||||
|
int digits = 0;
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
char ch = v[i];
|
||||||
|
if (ch >= '0' && ch <= '9') {
|
||||||
|
digits++;
|
||||||
|
value = value * 10 + (ch - '0');
|
||||||
|
} else {
|
||||||
|
return defValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return digits > 0 ? value : defValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// read as long value
|
||||||
|
@property inout(long) integer() inout {
|
||||||
|
final switch(_type) with(SettingType) {
|
||||||
|
case STRING:
|
||||||
|
return parseLong(_store.str);
|
||||||
|
case INTEGER:
|
||||||
|
return _store.integer;
|
||||||
|
case UINTEGER:
|
||||||
|
return cast(long)_store.uinteger;
|
||||||
|
case FLOAT:
|
||||||
|
return cast(long)_store.floating;
|
||||||
|
case TRUE:
|
||||||
|
return 1;
|
||||||
|
case FALSE:
|
||||||
|
case NULL:
|
||||||
|
case ARRAY:
|
||||||
|
case OBJECT:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// set long value for object
|
||||||
|
@property long integer(long v) {
|
||||||
|
if (_type != SettingType.INTEGER)
|
||||||
|
clear(SettingType.INTEGER);
|
||||||
|
_store.integer = v;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// read as ulong value
|
||||||
|
@property inout(long) uinteger() inout {
|
||||||
|
final switch(_type) with(SettingType) {
|
||||||
|
case STRING:
|
||||||
|
return parseULong(_store.str);
|
||||||
|
case INTEGER:
|
||||||
|
return cast(ulong)_store.integer;
|
||||||
|
case UINTEGER:
|
||||||
|
return _store.uinteger;
|
||||||
|
case FLOAT:
|
||||||
|
return cast(ulong)_store.floating;
|
||||||
|
case TRUE:
|
||||||
|
return 1;
|
||||||
|
case FALSE:
|
||||||
|
case NULL:
|
||||||
|
case ARRAY:
|
||||||
|
case OBJECT:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// set ulong value for object
|
||||||
|
@property ulong uinteger(ulong v) {
|
||||||
|
if (_type != SettingType.UINTEGER)
|
||||||
|
clear(SettingType.UINTEGER);
|
||||||
|
_store.uinteger = v;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// read as double value
|
||||||
|
@property inout(double) floating() inout {
|
||||||
|
final switch(_type) with(SettingType) {
|
||||||
|
case STRING:
|
||||||
|
return 0; //parseULong(_store.str);
|
||||||
|
case INTEGER:
|
||||||
|
return cast(double)_store.integer;
|
||||||
|
case UINTEGER:
|
||||||
|
return cast(double)_store.uinteger;
|
||||||
|
case FLOAT:
|
||||||
|
return _store.floating;
|
||||||
|
case TRUE:
|
||||||
|
return 1;
|
||||||
|
case FALSE:
|
||||||
|
case NULL:
|
||||||
|
case ARRAY:
|
||||||
|
case OBJECT:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// set ulong value for object
|
||||||
|
@property double floating(double v) {
|
||||||
|
if (_type != SettingType.FLOAT)
|
||||||
|
clear(SettingType.FLOAT);
|
||||||
|
_store.floating = v;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// parse string as boolean; supports 1, 0, y, n, yes, no, t, f, true, false; returns defValue if cannot be parsed
|
||||||
|
static bool parseBool(inout string v, bool defValue = false) {
|
||||||
|
int len = cast(int)v.length;
|
||||||
|
if (len == 0)
|
||||||
|
return defValue;
|
||||||
|
char ch = v[0];
|
||||||
|
if (len == 1) {
|
||||||
|
if (ch == '1' || ch == 'y' || ch == 't')
|
||||||
|
return true;
|
||||||
|
if (ch == '1' || ch == 'y' || ch == 't')
|
||||||
|
return false;
|
||||||
|
return defValue;
|
||||||
|
}
|
||||||
|
if (v.equal("yes") || v.equal("true"))
|
||||||
|
return true;
|
||||||
|
if (v.equal("no") || v.equal("false"))
|
||||||
|
return false;
|
||||||
|
return defValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// read as boolean value
|
||||||
|
@property inout(bool) boolean() inout {
|
||||||
|
final switch(_type) with(SettingType) {
|
||||||
|
case STRING:
|
||||||
|
return parseBool(_store.str);
|
||||||
|
case INTEGER:
|
||||||
|
return _store.integer != 0;
|
||||||
|
case UINTEGER:
|
||||||
|
return _store.uinteger != 0;
|
||||||
|
case FLOAT:
|
||||||
|
return _store.floating != 0;
|
||||||
|
case TRUE:
|
||||||
|
return true;
|
||||||
|
case FALSE:
|
||||||
|
case NULL:
|
||||||
|
return false;
|
||||||
|
case ARRAY:
|
||||||
|
return !_store.array.empty;
|
||||||
|
case OBJECT:
|
||||||
|
return _store.map && !_store.map.empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// set bool value for object
|
||||||
|
@property bool boolean(bool v) {
|
||||||
|
if (_type == SettingType.TRUE) {
|
||||||
|
if (!v) _type = SettingType.FALSE;
|
||||||
|
} else if (_type == SettingType.FALSE) {
|
||||||
|
if (v) _type = SettingType.TRUE;
|
||||||
|
} else {
|
||||||
|
clear(v ? SettingType.TRUE : SettingType.FALSE);
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get number of elements for array or map, returns 0 for other types
|
||||||
|
int length() inout {
|
||||||
|
if (_type == SettingType.ARRAY) {
|
||||||
|
return cast(int)_store.array.list.length;
|
||||||
|
} else if (_type == SettingType.OBJECT) {
|
||||||
|
return _store.map ? cast(int)_store.map.list.length : 0;
|
||||||
|
} else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// for array or object returns item by index, null if index is out of bounds or setting is neither array nor object
|
||||||
|
Setting opIndex(int index) {
|
||||||
|
if (_type == SettingType.ARRAY) {
|
||||||
|
return _store.array.get(index);
|
||||||
|
} else if (_type == SettingType.OBJECT) {
|
||||||
|
if (!_store.map)
|
||||||
|
return null;
|
||||||
|
return _store.map.get(index);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// array methods
|
||||||
|
/// sets value for item by index
|
||||||
|
T opIndexAssign(T)(T value, int index) {
|
||||||
|
if (_type != SettingType.ARRAY)
|
||||||
|
clear(SettingType.ARRAY);
|
||||||
|
static if (is(value == Setting)) {
|
||||||
|
_store.array.set(index, value, this);
|
||||||
|
} else {
|
||||||
|
if (index >= 0 && index < _store.array.list.length) {
|
||||||
|
// existing item
|
||||||
|
Setting item = _store.array.list[index];
|
||||||
|
} else {
|
||||||
|
// create new item
|
||||||
|
_store.array.set(index, new Setting(value), this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
version (AAA): // comment out
|
||||||
|
|
||||||
/// access to settings
|
/// access to settings
|
||||||
/// keys may be either simple key identifier or path delimited by / (e.g. setting1/subsetting2/subsetting15)
|
/// keys may be either simple key identifier or path delimited by / (e.g. setting1/subsetting2/subsetting15)
|
||||||
interface Settings {
|
interface Settings {
|
||||||
|
|
Loading…
Reference in New Issue