Преглед на файлове

Commit changes over past time period

Billy Barrow преди 1 година
родител
ревизия
8e947d6bca

+ 10 - 1
src/lib/Collections/BinaryData.vala

@@ -2,7 +2,7 @@ using Invercargill.Convert;
 
 namespace Invercargill {
 
-    public class BinaryData : Enumerable<uint8> {
+    public class BinaryData : Enumerable<uint8>, Promotion<uint8> {
 
         public enum Endianness {
             Native,
@@ -292,6 +292,15 @@ namespace Invercargill {
             return amount != 0;
         }
 
+        public Enumerable<uint8> wrap(Enumerable<uint8> enumerable) {
+            chunks = Invercargill.single(enumerable);
+            return this;
+        }
+
+        public bool can_wrap(Type element_type) {
+            return element_type.is_a(typeof(uint8));
+        }
+
     }
 
 }

+ 33 - 11
src/lib/Collections/Vector.vala

@@ -4,8 +4,8 @@ namespace Invercargill {
 
         private T[] array;
         private int n_items = 0;
-        private SafeReadFunc<T> safe_read;
-        private SafeWriteFunc<T> safe_write;
+        private SafeReadFunc<T>? safe_read;
+        private SafeWriteFunc<T>? safe_write;
 
         private const int INITIAL_SIZE = 2;
 
@@ -22,8 +22,15 @@ namespace Invercargill {
         public override T[] to_array () {
             lock(array) {
                 var a2 = new T[n_items];
-                for(var i = 0; i < n_items; i++) {
-                    safe_write(a2, i, safe_read(array, i));
+                if(safe_write != null) {
+                    for(var i = 0; i < n_items; i++) {
+                        safe_write(a2, i, array_read(i));
+                    }
+                }
+                else {
+                    for(var i = 0; i < n_items; i++) {
+                        a2[i] = array[i];
+                    }
                 }
                 return a2;
             }
@@ -32,7 +39,7 @@ namespace Invercargill {
         public void add(T item) {
             lock(array) {
                 ensure_room(1);
-                safe_write(array, n_items, item);
+                array_write(n_items, item);
                 n_items++;
             }
         }
@@ -47,7 +54,7 @@ namespace Invercargill {
                     e = new IndexError.INDEX_EXCEEDS_UPPER_BOUNDS(@"Tried to access index $(index) on a vector with $(n_items) item(s)");
                 }
                 else {
-                    return safe_read(array, index);
+                    return array_read(index);
                 }
             }
             throw e;
@@ -58,7 +65,7 @@ namespace Invercargill {
                 if(index < 0 || index >= n_items) {
                     return null;
                 }
-                return safe_read(array, index);
+                return array_read(index);
             }
         }
 
@@ -72,7 +79,7 @@ namespace Invercargill {
                     e = new IndexError.INDEX_EXCEEDS_UPPER_BOUNDS(@"Tried to set index $(index) on a vector with $(n_items) item(s)");
                 }
                 else {
-                    safe_write(array, index, value);
+                    array_write(index, value);
                     return;
                 }
             }
@@ -117,7 +124,7 @@ namespace Invercargill {
                 else {
                     for(int i = index; i < n_items; i++) {
                         if(i+1 < n_items) {
-                            safe_write(array, i, safe_read(array, i+1));
+                            array_write(i, array_read(i+1));
                             continue;
                         }
                         array[i] = null;
@@ -139,7 +146,7 @@ namespace Invercargill {
                     e = new SequenceError.NO_ELEMENTS("The sequence contains no elements");
                 }
                 else {
-                    return safe_read(array, n_items -1);
+                    return array_read(n_items -1);
                 }
             }
             throw e;
@@ -155,11 +162,26 @@ namespace Invercargill {
                     return null;
                 }
                 else {
-                    return safe_read(array, n_items -1);
+                    return array_read(n_items -1);
                 }
             }
         }
 
+        private void array_write(int index, T item) {
+            if(safe_write != null) {
+                safe_write(array, index, item);
+                return;
+            }
+            array[index] = item;
+        }
+
+        private T array_read(int index) {
+            if(safe_read != null) {
+                return safe_read(array, index);
+            }
+            return array[index];
+        }
+
         private class VectorTracker<T> : Tracker<T> {
 
             private T? next_item = null;

+ 399 - 0
src/lib/Concrete/Numbers/Implementations.vala

@@ -0,0 +1,399 @@
+namespace Invercargill {
+
+    public class SignedNativeIntegers : NumberEnumerable<int> {
+        public override bool can_wrap(GLib.Type element_type) {
+            return element_type.is_a(typeof(int));
+        }
+        protected override int convert(int i) {
+            return i;
+        }
+        protected override bool greater_than(int a, int b) {
+            return a > b;
+        }
+        protected override bool less_than(int a, int b) {
+            return a < b;
+        }
+        protected override bool equal_to(int a, int b) {
+            return a == b;
+        }
+        protected override int add(int a, int b) {
+            return a + b;
+        }
+        protected override int subtract(int a, int b) {
+            return a - b;
+        }
+        protected override int multiply(int a, int b) {
+            return a * b;
+        }
+        protected override int divide(int a, int b) {
+            return a / b;
+        }
+        protected override int zero() {
+            return 0;
+        }        
+    }
+
+    public class UsignedNativeIntegers : NumberEnumerable<uint> {
+        public override bool can_wrap(GLib.Type element_type) {
+            return element_type.is_a(typeof(uint));
+        }
+        protected override uint convert(int i) {
+            return i;
+        }
+        protected override bool greater_than(uint a, uint b) {
+            return a > b;
+        }
+        protected override bool less_than(uint a, uint b) {
+            return a < b;
+        }
+        protected override bool equal_to(uint a, uint b) {
+            return a == b;
+        }
+        protected override uint add(uint a, uint b) {
+            return a + b;
+        }
+        protected override uint subtract(uint a, uint b) {
+            return a - b;
+        }
+        protected override uint multiply(uint a, uint b) {
+            return a * b;
+        }
+        protected override uint divide(uint a, uint b) {
+            return a / b;
+        }
+        protected override uint zero() {
+            return 0;
+        }      
+    }
+
+    public class Signed8BitIntegers : NumberEnumerable<int8> {
+        public override bool can_wrap(GLib.Type element_type) {
+            return element_type.is_a(typeof(int8));
+        }
+        protected override int8 convert(int i) {
+            return (int8)i;
+        }
+        protected override bool greater_than(int8 a, int8 b) {
+            return a > b;
+        }
+        protected override bool less_than(int8 a, int8 b) {
+            return a < b;
+        }
+        protected override bool equal_to(int8 a, int8 b) {
+            return a == b;
+        }
+        protected override int8 add(int8 a, int8 b) {
+            return a + b;
+        }
+        protected override int8 subtract(int8 a, int8 b) {
+            return a - b;
+        }
+        protected override int8 multiply(int8 a, int8 b) {
+            return a * b;
+        }
+        protected override int8 divide(int8 a, int8 b) {
+            return a / b;
+        }
+        protected override int8 zero() {
+            return 0;
+        }      
+    }
+
+    public class Unsigned8BitIntegers : NumberEnumerable<uint8> {
+        public override bool can_wrap(GLib.Type element_type) {
+            return element_type.is_a(typeof(uint8));
+        }
+        protected override uint8 convert(int i) {
+            return (uint8)i;
+        }
+        protected override bool greater_than(uint8 a, uint8 b) {
+            return a > b;
+        }
+        protected override bool less_than(uint8 a, uint8 b) {
+            return a < b;
+        }
+        protected override bool equal_to(uint8 a, uint8 b) {
+            return a == b;
+        }
+        protected override uint8 add(uint8 a, uint8 b) {
+            return a + b;
+        }
+        protected override uint8 subtract(uint8 a, uint8 b) {
+            return a - b;
+        }
+        protected override uint8 multiply(uint8 a, uint8 b) {
+            return a * b;
+        }
+        protected override uint8 divide(uint8 a, uint8 b) {
+            return a / b;
+        }
+        protected override uint8 zero() {
+            return 0;
+        }      
+    }
+
+    public class Signed16BitIntegers : NumberEnumerable<int16> {
+        public override bool can_wrap(GLib.Type element_type) {
+            return element_type.is_a(typeof(int16));
+        }
+        protected override int16 convert(int i) {
+            return (int16)i;
+        }
+        protected override bool greater_than(int16 a, int16 b) {
+            return a > b;
+        }
+        protected override bool less_than(int16 a, int16 b) {
+            return a < b;
+        }
+        protected override bool equal_to(int16 a, int16 b) {
+            return a == b;
+        }
+        protected override int16 add(int16 a, int16 b) {
+            return a + b;
+        }
+        protected override int16 subtract(int16 a, int16 b) {
+            return a - b;
+        }
+        protected override int16 multiply(int16 a, int16 b) {
+            return a * b;
+        }
+        protected override int16 divide(int16 a, int16 b) {
+            return a / b;
+        }
+        protected override int16 zero() {
+            return 0;
+        }      
+    }
+
+    public class Unsigned16BitIntegers : NumberEnumerable<uint16> {
+        public override bool can_wrap(GLib.Type element_type) {
+            return element_type.is_a(typeof(uint16));
+        }
+        protected override uint16 convert(int i) {
+            return (uint16)i;
+        }
+        protected override bool greater_than(uint16 a, uint16 b) {
+            return a > b;
+        }
+        protected override bool less_than(uint16 a, uint16 b) {
+            return a < b;
+        }
+        protected override bool equal_to(uint16 a, uint16 b) {
+            return a == b;
+        }
+        protected override uint16 add(uint16 a, uint16 b) {
+            return a + b;
+        }
+        protected override uint16 subtract(uint16 a, uint16 b) {
+            return a - b;
+        }
+        protected override uint16 multiply(uint16 a, uint16 b) {
+            return a * b;
+        }
+        protected override uint16 divide(uint16 a, uint16 b) {
+            return a / b;
+        }
+        protected override uint16 zero() {
+            return 0;
+        }      
+    }
+
+    public class Signed32BitIntegers : NumberEnumerable<int32> {
+        public override bool can_wrap(GLib.Type element_type) {
+            return element_type.is_a(typeof(int32));
+        }
+        protected override int32 convert(int i) {
+            return (int32)i;
+        }
+        protected override bool greater_than(int32 a, int32 b) {
+            return a > b;
+        }
+        protected override bool less_than(int32 a, int32 b) {
+            return a < b;
+        }
+        protected override bool equal_to(int32 a, int32 b) {
+            return a == b;
+        }
+        protected override int32 add(int32 a, int32 b) {
+            return a + b;
+        }
+        protected override int32 subtract(int32 a, int32 b) {
+            return a - b;
+        }
+        protected override int32 multiply(int32 a, int32 b) {
+            return a * b;
+        }
+        protected override int32 divide(int32 a, int32 b) {
+            return a / b;
+        }
+        protected override int32 zero() {
+            return 0;
+        }      
+    }
+
+    public class Unsigned32BitIntegers : NumberEnumerable<uint32> {
+        public override bool can_wrap(GLib.Type element_type) {
+            return element_type.is_a(typeof(uint32));
+        }
+        protected override uint32 convert(int i) {
+            return (uint32)i;
+        }
+        protected override bool greater_than(uint32 a, uint32 b) {
+            return a > b;
+        }
+        protected override bool less_than(uint32 a, uint32 b) {
+            return a < b;
+        }
+        protected override bool equal_to(uint32 a, uint32 b) {
+            return a == b;
+        }
+        protected override uint32 add(uint32 a, uint32 b) {
+            return a + b;
+        }
+        protected override uint32 subtract(uint32 a, uint32 b) {
+            return a - b;
+        }
+        protected override uint32 multiply(uint32 a, uint32 b) {
+            return a * b;
+        }
+        protected override uint32 divide(uint32 a, uint32 b) {
+            return a / b;
+        }
+        protected override uint32 zero() {
+            return 0;
+        }      
+    }
+
+    public class Signed64BitIntegers : NumberEnumerable<int64?> {
+        public override bool can_wrap(GLib.Type element_type) {
+            return element_type.is_a(typeof(int64?));
+        }
+        protected override int64? convert(int i) {
+            return (int64)i;
+        }
+        protected override bool greater_than(int64? a, int64? b) {
+            return a > b;
+        }
+        protected override bool less_than(int64? a, int64? b) {
+            return a < b;
+        }
+        protected override bool equal_to(int64? a, int64? b) {
+            return a == b;
+        }
+        protected override int64? add(int64? a, int64? b) {
+            return a + b;
+        }
+        protected override int64? subtract(int64? a, int64? b) {
+            return a - b;
+        }
+        protected override int64? multiply(int64? a, int64? b) {
+            return a * b;
+        }
+        protected override int64? divide(int64? a, int64? b) {
+            return a / b;
+        }
+        protected override int64? zero() {
+            return 0;
+        }      
+    }
+
+    public class Unsigned64BitIntegers : NumberEnumerable<uint64?> {
+        public override bool can_wrap(GLib.Type element_type) {
+            return element_type.is_a(typeof(uint64?));
+        }
+        protected override uint64? convert(int i) {
+            return (uint64)i;
+        }
+        protected override bool greater_than(uint64? a, uint64? b) {
+            return a > b;
+        }
+        protected override bool less_than(uint64? a, uint64? b) {
+            return a < b;
+        }
+        protected override bool equal_to(uint64? a, uint64? b) {
+            return a == b;
+        }
+        protected override uint64? add(uint64? a, uint64? b) {
+            return a + b;
+        }
+        protected override uint64? subtract(uint64? a, uint64? b) {
+            return a - b;
+        }
+        protected override uint64? multiply(uint64? a, uint64? b) {
+            return a * b;
+        }
+        protected override uint64? divide(uint64? a, uint64? b) {
+            return a / b;
+        }
+        protected override uint64? zero() {
+            return 0;
+        }      
+    }
+
+    public class Doubles : NumberEnumerable<double?> {
+        public override bool can_wrap(GLib.Type element_type) {
+            return element_type.is_a(typeof(double?));
+        }
+        protected override double? convert(int i) {
+            return (double?)i;
+        }
+        protected override bool greater_than(double? a, double? b) {
+            return a > b;
+        }
+        protected override bool less_than(double? a, double? b) {
+            return a < b;
+        }
+        protected override bool equal_to(double? a, double? b) {
+            return a == b;
+        }
+        protected override double? add(double? a, double? b) {
+            return a + b;
+        }
+        protected override double? subtract(double? a, double? b) {
+            return a - b;
+        }
+        protected override double? multiply(double? a, double? b) {
+            return a * b;
+        }
+        protected override double? divide(double? a, double? b) {
+            return a / b;
+        }
+        protected override double? zero() {
+            return 0;
+        }      
+    }
+
+    public class Floats : NumberEnumerable<float?> {
+        public override bool can_wrap(GLib.Type element_type) {
+            return element_type.is_a(typeof(float?));
+        }
+        protected override float? convert(int i) {
+            return (float?)i;
+        }
+        protected override bool greater_than(float? a, float? b) {
+            return a > b;
+        }
+        protected override bool less_than(float? a, float? b) {
+            return a < b;
+        }
+        protected override bool equal_to(float? a, float? b) {
+            return a == b;
+        }
+        protected override float? add(float? a, float? b) {
+            return a + b;
+        }
+        protected override float? subtract(float? a, float? b) {
+            return a - b;
+        }
+        protected override float? multiply(float? a, float? b) {
+            return a * b;
+        }
+        protected override float? divide(float? a, float? b) {
+            return a / b;
+        }
+        protected override float? zero() {
+            return 0;
+        }      
+    }
+
+}

+ 76 - 0
src/lib/Concrete/Numbers/NumberEnumerable.vala

@@ -0,0 +1,76 @@
+namespace Invercargill {
+
+    public abstract class NumberEnumerable<T> : ProxyEnumerable<T>, Promotion<T> {
+        public abstract bool can_wrap (GLib.Type element_type);
+
+        protected abstract bool greater_than(T a, T b);
+        protected abstract bool less_than(T a, T b);
+        protected abstract bool equal_to(T a, T b);
+        protected abstract T add(T a, T b);
+        protected abstract T subtract(T a, T b);
+        protected abstract T multiply(T a, T b);
+        protected abstract T divide(T a, T b);
+        protected abstract T zero();
+        protected abstract T convert(int i);
+
+        public virtual T average() {
+            return divide(sum(), convert(count()));
+        }
+        public virtual T sum() {
+            return aggrigate<T>(zero(), add);
+        }
+        public virtual T product() {
+            T number = zero();
+            var first = true;
+            foreach (var item in this) {
+                if(first) {
+                    first = false;
+                    number = item;
+                    continue;
+                }
+                number = multiply(number, item);
+            }
+            return number;
+        }
+        public new virtual T min() {
+            T value = null;
+            var first = true;
+            foreach (var i in this) {
+                if(first) {
+                    first = false;
+                    value = i;
+                    continue;
+                }
+                if(less_than(i, value)) {
+                    value = i;
+                }
+            }
+
+            return value;
+        }
+
+        public new virtual T max() {
+            T value = null;
+            var first = true;
+            foreach (var i in this) {
+                if(first) {
+                    first = false;
+                    value = i;
+                    continue;
+                }
+                if(greater_than(i, value)) {
+                    value = i;
+                }
+            }
+
+            return value;
+        }
+
+        public Enumerable<T> wrap (Enumerable<T> enumerable) {
+            inner = enumerable;
+            return this;
+        }
+
+    }
+
+}

+ 188 - 0
src/lib/Concrete/ProxyEnumerable.vala

@@ -0,0 +1,188 @@
+
+namespace Invercargill {
+
+    public abstract class ProxyEnumerable<T> : Enumerable<T> {
+
+        protected Enumerable<T> inner { get; set; }
+
+        public override Tracker<T> get_tracker() {
+            return inner.get_tracker();
+        }
+
+        public override bool iterate_if(PredicateDelegate<T> handler) {
+            return inner.iterate_if(handler);
+        }
+
+        public override void iterate(ItemDelegate<T> handler) {
+            inner.iterate(handler);
+        }
+
+        public override Series<T> to_series() {
+            return inner.to_series();
+        }
+    
+        public override Gee.Collection<T> to_gee_collection() {
+            return inner.to_gee_collection();
+        }
+    
+        public override Tracker<T> iterator() {
+            return inner.iterator();
+        }
+    
+        public override T[] to_array() {
+            return inner.to_array();
+        }
+    
+        public override int count() {
+            return inner.count();
+        }
+    
+        public override bool any(PredicateDelegate<T> predicate = (i) => true) {
+            return inner.any(predicate);
+        }
+    
+        public override bool all(PredicateDelegate<T> predicate) {
+            return inner.all(predicate);
+        }
+    
+        public override bool no(PredicateDelegate<T> predicate = (i) => true) {
+            return inner.no(predicate);
+        }
+    
+        public override Enumerable<T> where(owned PredicateDelegate<T> predicate) {
+            return inner.where((owned)predicate);
+        }
+    
+        public override Enumerable<Tout> select<Tout>(owned TransformDelegate<T, Tout> transform) {
+            return inner.select((owned)transform);
+        }
+    
+        public override Enumerable<Tout> select_many<Tout>(owned TransformDelegate<T, Enumerable<Tout>> transform) {
+            return inner.select_many((owned)transform);
+        }
+    
+        public override Enumerable<T> sort(owned CompareDelegate<T> compare) {
+            return inner.sort((owned)compare);
+        }
+    
+        public override Enumerable<T> concat(Enumerable<T> other) {
+            return inner.concat(other);
+        }
+    
+        public override Enumerable<T> take(int count) {
+            return inner.take(count);
+        }
+    
+        public override Enumerable<T> skip(int count) {
+            return inner.skip(count);
+        }
+    
+        public override Enumerable<Tout> cast<Tout>() {
+            return inner.cast<Tout>();
+        }
+    
+        public override Enumerable<Tout> parallel_select<Tout>(owned TransformDelegate<T, Tout> transform, uint workers = 0) {
+            return inner.parallel_select((owned)transform, workers);
+        }
+    
+        public override int parallel_iterate(ItemDelegate<T> handler, uint workers = 0) {
+            return inner.parallel_iterate(handler, workers);
+        }
+    
+        public override Enumerable<SelectionContext<T, Tout>> contextualised_select<Tout>(owned TransformDelegate<T, Tout> transform) {
+            return inner.contextualised_select((owned)transform);
+        }
+    
+        public override Tout aggrigate<Tout>(Tout initial, AggrigateDelegate<Tout, T> aggrigate_func) {
+            return inner.aggrigate(initial, aggrigate_func);
+        }
+    
+        public override T max(TransformDelegate<T, int> int_delegate) {
+            return inner.max(int_delegate);
+        }
+    
+        public override T min(TransformDelegate<T, int> int_delegate) {
+            return inner.min(int_delegate);
+        }
+    
+        public override bool contains(T item) {
+            return inner.contains(item);
+        }
+    
+        public override Enumerable<Pair<T, Tother>> pair<Tother>(Enumerable<Tother> other) {
+            return inner.pair(other);
+        }
+    
+        public override Enumerable<T> zip(Enumerable<T> other) {
+            return inner.zip(other);
+        }
+    
+        public override Enumerable<Tout> fork<Tout>(owned TransformDelegate<T, Tout> fork1, owned TransformDelegate<T, Tout> fork2) {
+            return inner.fork((owned)fork1, (owned)fork2);
+        }
+    
+        public override Enumerable<Tout> fork_many<Tout>(owned TransformDelegate<T, Enumerable<Tout>> fork1, owned TransformDelegate<T, Enumerable<Tout>> fork2) {
+            return inner.fork_many((owned)fork1, (owned)fork2);
+        }
+    
+        public override bool matches(Enumerable<T> other, EqualityDelegate<T> equals) {
+            return inner.matches(other, equals);
+        }
+    
+        public override Enumerable<T> with(T item) {
+            return inner.with(item);
+        }
+    
+        public override T first(owned PredicateDelegate<T>? predicate = null) throws SequenceError {
+            return inner.first((owned)predicate);
+        }
+    
+        public override T? first_or_default(owned PredicateDelegate<T>? predicate = null) {
+            return inner.first_or_default((owned)predicate);
+        }
+    
+        public override T last(owned PredicateDelegate<T>? predicate = null) throws SequenceError {
+            return inner.last((owned)predicate);
+        }
+    
+        public override T? last_or_default(owned PredicateDelegate<T>? predicate = null) {
+            return inner.last_or_default((owned)predicate);
+        }
+    
+        public override T single(owned PredicateDelegate<T>? predicate = null) throws SequenceError {
+            return inner.single((owned)predicate);
+        }
+    
+        public override T? single_or_default(owned PredicateDelegate<T>? predicate = null) throws SequenceError {
+            return inner.single_or_default((owned)predicate);
+        }
+    
+        public override string to_string(TransformDelegate<T, string> stringifier, string separator = "") {
+            return inner.to_string(stringifier, separator);
+        }
+    
+        public override Object[] to_object_array() throws SequenceError {
+            return inner.to_object_array();
+        }
+    
+        public override Vector<T> to_vector() {
+            return inner.to_vector();
+        }
+    
+        public override Type element_type { 
+            get {
+                return inner.element_type;
+            }
+        }
+    
+        public override TPromotion try_promote_to<TPromotion>() throws PromotionError {
+            return inner.try_promote_to<TPromotion>();
+        }
+    
+        public override TPromotion promote_to<TPromotion>() {
+            return inner.promote_to<TPromotion>();
+        }
+
+    }
+
+}

+ 82 - 0
src/lib/Enumerable.vala

@@ -144,6 +144,48 @@ namespace Invercargill {
             return aggrigate;
         }
 
+        public virtual T max(TransformDelegate<T, int> int_delegate) {
+            T item = null;
+            var first = true;
+            var value = 0;
+            foreach (var i in this) {
+                if(first) {
+                    first = false;
+                    item = i;
+                    value = int_delegate(i);
+                    continue;
+                }
+                var item_value = int_delegate(i);
+                if(item_value > value) {
+                    value = item_value;
+                    item = i;
+                }
+            }
+
+            return item;
+        }
+
+        public virtual T min(TransformDelegate<T, int> int_delegate) {
+            T item = null;
+            var first = true;
+            var value = 0;
+            foreach (var i in this) {
+                if(first) {
+                    first = false;
+                    item = i;
+                    value = int_delegate(i);
+                    continue;
+                }
+                var item_value = int_delegate(i);
+                if(item_value < value) {
+                    value = item_value;
+                    item = i;
+                }
+            }
+
+            return item;
+        }
+
         public virtual bool contains(T item) {
             return any(i => i == item);
         }
@@ -265,6 +307,46 @@ namespace Invercargill {
             return vector;
         }
 
+        public virtual Type element_type { get {
+            return typeof(T);
+        }}
+
+        public virtual TPromotion try_promote_to<TPromotion>() throws PromotionError {
+            var type = typeof(TPromotion);
+            if(get_type().is_a(type)) {
+                // Don't promote if we are already target type
+                return this;
+            }
+            if(!type.is_instantiatable()) {
+                throw new PromotionError.INVALID_PROMOTION_TYPE(@"Provided promotion type $(type.name()) is not instansiatable.");
+            }
+            if(!type.is_a(typeof(Promotion))) {
+                throw new PromotionError.INVALID_PROMOTION_TYPE(@"Provided promotion type $(type.name()) does not implement Invercargill.Promotion.");
+            }
+            if(!type.is_a(typeof(Enumerable))) {
+                throw new PromotionError.INVALID_PROMOTION_TYPE(@"Provided promotion type $(type.name()) does not implement Invercargill.Enumerable.");
+            }
+
+            var promotion = Object.new(type);
+            if(!((Promotion)promotion).can_wrap(element_type)) {
+                throw new PromotionError.INCOMPATIBLE_ELEMENT_TYPE(@"Enumerable has an element type of $(element_type.name()) which cannot be wrapped by $(type.name())");
+            }
+
+            return ((Promotion)promotion).wrap(this);
+        }
+
+        public virtual TPromotion promote_to<TPromotion>() {
+            try {
+                return try_promote_to<TPromotion>();
+            }
+            catch (PromotionError error) {
+                var base_type = get_type();
+                var type = typeof(TPromotion);
+                critical(@"Cannot promote type $(base_type.name()) to $(type.name()): $(error.message)");
+                assert_not_reached();
+            }
+        }
+
     }
 
 }

+ 5 - 0
src/lib/Errors.vala

@@ -15,4 +15,9 @@ namespace Invercargill {
         INDEX_EXCEEDS_LOWER_BOUNDS,
         KEY_NOT_FOUND
     }
+
+    public errordomain PromotionError {
+        INVALID_PROMOTION_TYPE,
+        INCOMPATIBLE_ELEMENT_TYPE
+    }
 }

+ 10 - 0
src/lib/Promotion.vala

@@ -0,0 +1,10 @@
+namespace Invercargill {
+    
+    public interface Promotion<T> {
+
+        public abstract Enumerable<T> wrap(Enumerable<T> enumerable);
+
+        public abstract bool can_wrap(Type element_type);
+    }
+
+}

+ 4 - 10
src/lib/Safety.vala

@@ -118,9 +118,6 @@ namespace Invercargill {
     internal double safely_read_double_from_array(double[] array, int index) {
         return ((double?[])array)[index];
     }
-    internal T read_from_array<T>(T[] array, int index) {
-        return array[index];
-    }
 
     internal void safely_assign_bool_to_array(bool[] array, int index, bool value) {
         ((bool[])array)[index] = (bool)value;
@@ -155,11 +152,8 @@ namespace Invercargill {
     internal void safely_assign_double_to_array(double[] array, int index, double value) {
         ((double?[])array)[index] = (double?)value;
     }
-    internal void assign_to_array<T>(T[] array, int index, T value) {
-        array[index] = value;
-    }
 
-    internal SafeReadFunc<T> get_safe_read_function_for<T>() {
+    internal SafeReadFunc<T>? get_safe_read_function_for<T>() {
         var t = typeof (T);
         if (t == typeof (bool)) {
             return (SafeReadFunc<T>)safely_read_bool_from_array;
@@ -194,10 +188,10 @@ namespace Invercargill {
         else if (t == typeof (double)) {
             return (SafeReadFunc<T>)safely_read_double_from_array;
         }
-        return (SafeReadFunc<T>)read_from_array<T>;
+        return null;
     }
 
-    internal SafeWriteFunc<T> get_safe_write_function_for<T>() {
+    internal SafeWriteFunc<T>? get_safe_write_function_for<T>() {
         var t = typeof (T);
         if (t == typeof (bool)) {
             return (SafeWriteFunc<T>)safely_assign_bool_to_array;
@@ -232,7 +226,7 @@ namespace Invercargill {
         else if (t == typeof (double)) {
             return (SafeWriteFunc<T>)safely_assign_double_to_array;
         }
-        return (SafeWriteFunc<T>)assign_to_array<T>;
+        return null;
     }
 
 }

+ 4 - 0
src/lib/meson.build

@@ -15,6 +15,7 @@ sources += files('Errors.vala')
 sources += files('SelectionContext.vala')
 sources += files('Convert.vala')
 sources += files('Safety.vala')
+sources += files('Promotion.vala')
 
 sources += files('Queries/Query.vala')
 sources += files('Queries/Transform.vala')
@@ -36,6 +37,9 @@ sources += files('Concrete/DirEnumerable.vala')
 sources += files('Concrete/ZipperEnumerable.vala')
 sources += files('Concrete/EmptyEnumerable.vala')
 sources += files('Concrete/Generator.vala')
+sources += files('Concrete/Numbers/NumberEnumerable.vala')
+sources += files('Concrete/Numbers/Implementations.vala')
+sources += files('Concrete/ProxyEnumerable.vala')
 
 sources += files('Collections/Series.vala')
 sources += files('Collections/Fifo.vala')

+ 0 - 1
src/meson.build

@@ -1,6 +1,5 @@
 project('invercargill', 'vala', 'c')
 subdir('lib')
-
 dependencies += invercargill_dep
 subdir('tests')
 

+ 44 - 0
src/tests/Integration/Numbers.vala

@@ -0,0 +1,44 @@
+using Invercargill;
+using Invercargill.Convert;
+
+void numbers_test() {
+
+    Test.add_func("/invercargill/numbers/average", () => {
+
+        var data = range(1, 60, 1).select<double?>(i => (double?)i);
+        var numbers = data.promote_to<Doubles>();
+        var average = numbers.average();
+
+        assert_cmpfloat(average, CompareOperator.EQ, 30);
+
+    });
+
+    Test.add_func("/invercargill/numbers/average-vector", () => {
+
+        var data = new Vector<int>();
+        data.add(5);
+        data.add(15);
+        data.add(10);
+
+        var numbers = data.promote_to<SignedNativeIntegers>();
+        var average = numbers.average();
+
+        assert_cmpfloat(average, CompareOperator.EQ, 10);
+
+    });
+
+
+    // THERE IS A BUG IN VECTORS WHEN THEY ARE DOUBLES, this is a problem with vectors, not "Doubles"
+    //  Test.add_func("/invercargill/numbers/average-vector-doubles", () => {
+    //      var data = new Vector<double?>();
+    //      data.add(5);
+    //      data.add(6);
+
+    //      var numbers = data.promote_to<Doubles>();
+    //      var average = numbers.average();
+
+    //      assert_cmpfloat(average, CompareOperator.EQ, 5.5);
+
+    //  });
+
+}

+ 27 - 0
src/tests/Integration/Promotion.vala

@@ -0,0 +1,27 @@
+using Invercargill;
+using Invercargill.Convert;
+
+void promotion_tests() {
+
+    Test.add_func("/invercargill/promotions/uint8_to_binarydata", () => {
+
+        var data = new Vector<uint8>();
+        data.add(1);
+        data.add(9);
+        data.add(7);
+
+        var base64 = data.promote_to<BinaryData>().to_base64();
+        
+        assert_cmpstr("AQAA", CompareOperator.EQ, base64);
+
+    });
+
+    Test.add_func("/invercargill/promotions/binarydata_to_binarydata", () => {
+
+        var data = (Enumerable<uint8>)new BinaryData.from_base64("AQAA");
+        var new_data = data.promote_to<BinaryData>();
+        
+        assert_true(data == new_data);
+    });
+
+}

+ 31 - 0
src/tests/Integration/Vector.vala

@@ -13,6 +13,32 @@ void vector_tests() {
         assert(vector.count() == 1);
     });
 
+    Test.add_func("/invercargill/structure/vector/add_strings", () => {
+
+        var vector = new Vector<string>();
+        vector.add("test string");
+
+        assert(vector.first_or_default() == "test string");
+        assert(vector.get_or_default(0) == "test string");
+        assert(vector.count() == 1);
+    });
+
+    Test.add_func("/invercargill/structure/vector/add_objects", () => {
+
+        var vector = new Vector<TestObject>();
+        var obj = new TestObject() {
+            string_value = "hello, world",
+            int_value = 1999
+        };
+        vector.add(obj);
+
+        assert(vector.first_or_default() == obj);
+        assert(vector.get_or_default(0) == obj);
+        assert(vector.first_or_default().int_value == 1999);
+        assert(vector.first_or_default().string_value == "hello, world");
+        assert(vector.count() == 1);
+    });
+
     Test.add_func("/invercargill/structure/vector/expand", () => {
 
         var vector = new Vector<int>();
@@ -199,4 +225,9 @@ void vector_tests() {
         
         assert(items.get_or_default(1) == 8);
     });
+}
+
+private class TestObject {
+    public string string_value { get; set; }
+    public int int_value { get; set; }
 }

+ 2 - 0
src/tests/TestRunner.vala

@@ -15,6 +15,8 @@ public static int main(string[] args) {
     vector_tests();
     series_tests();
     array_tests();
+    promotion_tests();
+    numbers_test();
 
     Test.run();
 

+ 2 - 0
src/tests/meson.build

@@ -14,6 +14,8 @@ sources += files('Integration/BinaryData.vala')
 sources += files('Integration/Vector.vala')
 sources += files('Integration/Series.vala')
 sources += files('Integration/Arrays.vala')
+sources += files('Integration/Promotion.vala')
+sources += files('Integration/Numbers.vala')
 
 sources += files('Speed/SpeedTest.vala')
 sources += files('Speed/Series.vala')