namespace Invercargill { // TODO: Reform Datum to have a type, and add specific to_x functions, with perhaps a to convenience function. // all of these can return errors // int as_int() for type NUMBER // int64 as_int64() for type NUMBER // uint64 as_uint64() for type NUMBER // ... // string as_string() for type STRING or NUMBER // Enumerable as_enumerable() for type ENUMERABLE // KeyValues as_keyvalues() for type KEY_VALUES or PROPERTIES // Properties as_properties() for type PROPERTIES // Add mappable interface with // protected PropertyMapper // public Properties to_properties() // public void populate(Properties props) public interface Elements : Enumerable { public virtual Enumerable elements_as() { return try_select((e, ref r) => e.try_get_as(out r)); } public virtual Enumerable assert_elements_as() { return select(e => e.assert_as()); } } private class ElementSeries : Series, Elements {} public interface Element : Object { public abstract bool assignable_to_type(Type type); public abstract Type? type(); public abstract bool is_null(); public abstract bool try_get_as(out T result); public virtual bool is_type(Type type) { return this.type().is_a(type); } public virtual bool assignable_to() { return assignable_to_type(typeof(T)); } public virtual bool @is() { return is_type(typeof(T)); } public virtual string type_name() { return type().name(); } public virtual T? @as() throws ElementError { T result; if(try_get_as(out result)) { return result; } throw new ElementError.INVALID_CONVERSION(@"Could not convert from $(type_name()) to $(typeof(T).name())."); } public virtual T? as_or_default() { T result; if(try_get_as(out result)) { return result; } return null; } public virtual T assert_as() { T result; if(try_get_as(out result)) { return result; } critical(@"Element.assert_as<$(typeof(T).name())> failed: Could not get $(this.get_type().name()) as type $(typeof(T).name())."); assert_not_reached(); } public virtual string to_string() { return @"Element[$(type_name())]"; } } public class NativeElement : Object, Element { private T object; public NativeElement(T obj) { object = obj; } public bool assignable_to_type(GLib.Type type) { if(is_type(type)) { return true; } if(typeof(T).is_a(typeof(Enumerable)) && type == typeof(Elements)) { return true; } return false; } public GLib.Type? type() { return typeof(T); } public bool is_null() { return object == null; } public bool try_get_as(out TOut result) { if(typeof(T).is_a(typeof(Enumerable)) && typeof(TOut) == typeof(Elements)) { result = (TOut)((Enumerable)object).to_elements(); return true; } if(assignable_to()) { result = (TOut)object; return true; } result = null; return false; } } public class NullElement : Object, Element { public bool assignable_to_type(GLib.Type type) { return true; } public GLib.Type? type() { return null; } public bool is_null() { return true; } public bool try_get_as(out T result) { result = null; return true; } public string to_string() { return "Element[null]"; } } }