فهرست منبع

Refactor BinaryData

Billy Barrow 2 هفته پیش
والد
کامیت
f40c6649ea

+ 215 - 0
src/lib/ByteComposition.vala

@@ -0,0 +1,215 @@
+using Invercargill.DataStructures;
+
+namespace Invercargill {
+
+    public class ByteComposition : Composition<uint8>, BinaryData {
+
+        public Endianness endianness { get; set; }
+
+        public ByteComposition() {
+            endianness = Endianness.Native;
+        }
+
+        public ByteComposition.from_enumerable(Enumerable<uint8> data) {
+            append(data);
+            endianness = Endianness.Native;
+        }
+
+        public ByteComposition.from_bytes(Bytes data) {
+            append(Wrap.array(data.get_data()));
+            endianness = Endianness.Native;
+        }
+
+        public ByteComposition.from_byte_array(uint8[] data) {
+            append(Wrap.array(data));
+            endianness = Endianness.Native;
+        }
+
+        public ByteComposition.from_base64(string data) {
+            append(Wrap.array(Base64.decode(data)));
+            endianness = Endianness.Native;
+        }
+
+        public ByteComposition.from_hex(string data) {
+            var groomed = data.replace(" ", "").replace("-", "").replace(":", "").replace("0x", "");
+            var buffer = new Buffer<uint8>(groomed.length/2);
+            for(var i = 0; i < groomed.length/2; i++) {
+                non_error(() => buffer[i] = (uint8)uint.parse(groomed[i*2:(i+1)*2], 16));
+            }
+            append(buffer);
+            endianness = Endianness.Native;
+        }
+
+        public void append_byte_array(uint8[] data) {
+            append(Wrap.array(data));
+        }
+
+        public void append_bytes(Bytes data) {
+            append_byte_array(data.get_data());
+        }
+
+        public void append_string(string str) {
+            append_byte_array(get_string_data(str));
+        }
+
+        public void append_base64(string str) {
+            append_byte_array(Base64.decode(str));
+        }
+
+        public void append_hex(string str) {
+            append(new ByteBuffer.from_hex(str));
+        }
+
+        public void prepend_byte_array(uint8[] data) {
+            prepend(Wrap.array(data));
+        }
+
+        public void prepend_bytes(Bytes data) {
+            prepend_byte_array(data.get_data());
+        }
+
+        public void prepend_string(string str) {
+            prepend_byte_array(get_string_data(str));
+        }
+
+        public void prepend_base64(string str) {
+            prepend_byte_array(Base64.decode(str));
+        }
+
+        public void prepend_hex(string str) {
+            prepend(new ByteBuffer.from_hex(str));
+        }
+        
+        private uint8[] get_string_data(string str) {
+            var data = str.data;
+            return data;
+        }
+
+        //  int64
+        public void append_int64(int64 value) {
+            var data = new ByteBuffer((uint)sizeof(int64));
+            non_error(() => data.set_int64(0, value, endianness));
+            append(data);
+        }
+
+        public void prepend_int64(int64 value) {
+            var data = new ByteBuffer((uint)sizeof(int64));
+            non_error(() => data.set_int64(0, value, endianness));
+            prepend(data);
+        }
+
+        //  uint64
+        public void append_uint64(uint64 value) {
+            var data = new ByteBuffer((uint)sizeof(uint64));
+            non_error(() => data.set_uint64(0, value, endianness));
+            append(data);
+        }
+
+        public void prepend_uint64(uint64 value) {
+            var data = new ByteBuffer((uint)sizeof(uint64));
+            non_error(() => data.set_uint64(0, value, endianness));
+            prepend(data);
+        }
+
+        //  int32
+        public void append_int32(int32 value) {
+            var data = new ByteBuffer((uint)sizeof(int32));
+            non_error(() => data.set_int32(0, value, endianness));
+            append(data);
+        }
+
+        public void prepend_int32(int32 value) {
+            var data = new ByteBuffer((uint)sizeof(int32));
+            non_error(() => data.set_int32(0, value, endianness));
+            prepend(data);
+        }
+
+        //  uint32
+        public void append_uint32(uint32 value) {
+            var data = new ByteBuffer((uint)sizeof(uint32));
+            non_error(() => data.set_uint32(0, value, endianness));
+            append(data);
+        }
+
+        public void prepend_uint32(uint32 value) {
+            var data = new ByteBuffer((uint)sizeof(uint32));
+            non_error(() => data.set_uint32(0, value, endianness));
+            prepend(data);
+        }
+
+        //  int16
+        public void append_int16(int16 value) {
+            var data = new ByteBuffer((uint)sizeof(int16));
+            non_error(() => data.set_int16(0, value, endianness));
+            append(data);
+        }
+
+        public void prepend_int16(int16 value) {
+            var data = new ByteBuffer((uint)sizeof(int16));
+            non_error(() => data.set_int16(0, value, endianness));
+            prepend(data);
+        }
+
+        //  uint16
+        public void append_uint16(uint16 value) {
+            var data = new ByteBuffer((uint)sizeof(uint16));
+            non_error(() => data.set_uint16(0, value, endianness));
+            append(data);
+        }
+
+        public void prepend_uint16(uint16 value) {
+            var data = new ByteBuffer((uint)sizeof(uint16));
+            non_error(() => data.set_uint16(0, value, endianness));
+            prepend(data);
+        }
+
+        //  int8
+        public void append_int8(int8 value) {
+            var data = new ByteBuffer((uint)sizeof(int8));
+            non_error(() => data.set_int8(0, value, endianness));
+            append(data);
+        }
+
+        public void prepend_int8(int8 value) {
+            var data = new ByteBuffer((uint)sizeof(int8));
+            non_error(() => data.set_int8(0, value, endianness));
+            prepend(data);
+        }
+
+        //  uint8
+        public void append_uint8(uint8 value) {
+            var data = new ByteBuffer((uint)sizeof(uint8));
+            non_error(() => data.set_uint8(0, value, endianness));
+            append(data);
+        }
+
+        public void prepend_uint8(uint8 value) {
+            var data = new ByteBuffer((uint)sizeof(uint8));
+            non_error(() => data.set_uint8(0, value, endianness));
+            prepend(data);
+        }
+
+        public bool read_in(Bytes? data, ref size_t amount) throws Error {
+            if(amount <= 0) {
+                return false;
+            }
+            if(data == null) {
+                return true;
+            }
+            if(data.length == 0) {
+                throw new ByteCompositionReadError.EMPTY_READ("Encounterd zero-length data object");
+            }
+            if(data.length > amount) {
+                throw new ByteCompositionReadError.BUFFER_OVERFLOW("Encountered more data than requested");
+            }
+
+            var bin = new uint8[data.length];
+            Memory.copy(bin, data.get_data(), data.length);
+            append_byte_array(bin);
+            amount -= data.length;
+            return amount != 0;
+        }
+
+    }
+
+}

+ 9 - 1
src/lib/Composition.vala

@@ -3,7 +3,7 @@ namespace Invercargill {
 
     public class Composition<T> : Enumerable<T> {
 
-        private DataStructures.Series<Enumerable<T>> enumerables = new DataStructures.Series<Enumerable<T>>();
+        protected DataStructures.Series<Enumerable<T>> enumerables = new DataStructures.Series<Enumerable<T>>();
 
         public override Tracker<T> get_tracker () {
             return enumerables.select_many<T>(i => i).get_tracker();
@@ -29,10 +29,18 @@ namespace Invercargill {
             enumerables.add_start (items);
         }
 
+        public void prepend_all(Enumerable<Enumerable<T>> items) {
+            enumerables.add_all_start (items);
+        }
+
         public void append(Enumerable<T> items) {
             enumerables.add (items);
         }
 
+        public void append_all(Enumerable<Enumerable<T>> items) {
+            enumerables.add_all (items);
+        }
+
         public void prepend_item(T item) {
             enumerables.add_start (Iterate.single(item));
         }

+ 0 - 506
src/lib/DataStructures/BinaryData.vala

@@ -1,506 +0,0 @@
-
-namespace Invercargill.DataStructures {
-
-    public class BinaryData : Enumerable<uint8>, Promotion<uint8>, Equatable<Enumerable<uint8>>, Hashable {
-
-        public enum Endianness {
-            Native,
-            BigEndian,
-            LittleEndian,
-        }
-
-        public Endianness endianness { get; set; }
-
-        private Enumerable<Enumerable<uint8>> chunks;
-
-        public override int? peek_count() {
-            return null;
-        }
-
-        public override EnumerableInfo get_info() {
-            return new EnumerableInfo.infer(this, EnumerableCategory.COMPUTED, chunks);
-        }
-
-        public override Tracker<uint8> get_tracker () {
-            return chunks.select_many<uint8>(s => s).get_tracker();
-        }
-
-        public BinaryData() {
-            chunks = new Series<Enumerable<uint8>>();
-            endianness = Endianness.Native;
-        }
-
-        public BinaryData.from_enumerable(Enumerable<uint8> data) {
-            chunks = Invercargill.single(data.to_buffer());
-            endianness = Endianness.Native;
-        }
-
-        public BinaryData.from_bytes(Bytes data) {
-            chunks = Invercargill.single(Wrap.array(data.get_data()));
-            endianness = Endianness.Native;
-        }
-
-        public BinaryData.from_byte_array(uint8[] data) {
-            chunks = Invercargill.single(Wrap.array(data));
-            endianness = Endianness.Native;
-        }
-
-        public BinaryData.from_base64(string data) {
-            chunks = Invercargill.single(Wrap.array(Base64.decode(data)));
-            endianness = Endianness.Native;
-        }
-
-        public BinaryData.from_hex(string data) {
-            var groomed = data.replace(" ", "").replace("-", "").replace(":", "").replace("0x", "");
-            var buffer = new Buffer<uint8>(groomed.length/2);
-            for(var i = 0; i < groomed.length/2; i++) {
-                non_error(() => buffer[i] = (uint8)uint.parse(groomed[i*2:(i+1)*2], 16));
-            }
-            chunks = Invercargill.single(buffer);
-            endianness = Endianness.Native;
-        }
-
-        public void append(Enumerable<uint8> data) {
-            lock(chunks) {
-                chunks = chunks.with(data);
-            }
-        }
-
-        public void append_all(Enumerable<Enumerable<uint8>> data) {
-            lock(chunks) {
-                chunks = chunks.concat(data.to_buffer());
-            }
-        }
-
-        public void prepend(Enumerable<uint8> data) {
-            lock(chunks) {
-                chunks = Invercargill.single(data).concat(chunks);
-            }
-        }
-
-        public void prepend_all(Enumerable<Enumerable<uint8>> data) {
-            lock(chunks) {
-                chunks = data.concat(chunks.to_buffer());
-            }
-        }
-
-        public void append_byte_array(uint8[] data) {
-            append(Wrap.array(data));
-        }
-
-        public void append_bytes(Bytes data) {
-            append_byte_array(data.get_data());
-        }
-
-        public void append_string(string str) {
-            append_byte_array(get_string_data(str));
-        }
-
-        public void prepend_byte_array(uint8[] data) {
-            prepend(Wrap.array(data));
-        }
-
-        public void prepend_bytes(Bytes data) {
-            prepend_byte_array(data.get_data());
-        }
-
-        public void prepend_string(string str) {
-            prepend_byte_array(get_string_data(str));
-        }
-        
-        private uint8[] get_string_data(string str) {
-            var data = str.data;
-            return data;
-        }
-
-        public void push_int64(int64 value) {
-            var chunk = new uint8[sizeof(int64)];
-            int64 val;
-            switch (endianness) {
-                case Endianness.Native:
-                    val = value;
-                    break;
-                case Endianness.BigEndian:
-                    val = value.to_big_endian();
-                    break;
-                case Endianness.LittleEndian:
-                    val = value.to_little_endian();
-                    break;
-            }            
-            Memory.copy(chunk, &val, sizeof(int64));
-            append(Wrap.array(chunk));
-        }
-
-        public int64? read_int64(int index) {
-            var data = skip(index).take((int)sizeof(int64)).to_array();
-            if(data.length != sizeof(int64))
-                return null;
-            int64 value = 0;
-            int64 val = 0;
-            Memory.copy(&value, data, sizeof(int64));
-            switch (endianness) {
-                case Endianness.Native:
-                    val = value;
-                    break;
-                case Endianness.BigEndian:
-                    val = value.to_big_endian();
-                    break;
-                case Endianness.LittleEndian:
-                    val = value.to_little_endian();
-                    break;
-            } 
-            return val;           
-        }
-
-        public void push_all_int64(Enumerable<int64?> values) {
-            values.iterate(i => push_int64(i));
-        }
-
-        public void push_uint64(uint64 value) {
-            var chunk = new uint8[sizeof(uint64)];
-            uint64 val;
-            switch (endianness) {
-                case Endianness.Native:
-                    val = value;
-                    break;
-                case Endianness.BigEndian:
-                    val = value.to_big_endian();
-                    break;
-                case Endianness.LittleEndian:
-                    val = value.to_little_endian();
-                    break;
-            }            
-            Memory.copy(chunk, &val, sizeof(uint64));
-            append(Wrap.array(chunk));
-        }
-
-
-        public uint64? read_uint64(int index) {
-            var data = skip(index).take((int)sizeof(uint64)).to_array();
-            if(data.length != sizeof(uint64))
-                return null;
-            uint64 value = 0;
-            uint64 val = 0;
-            Memory.copy(&value, data, sizeof(uint64));
-            switch (endianness) {
-                case Endianness.Native:
-                    val = value;
-                    break;
-                case Endianness.BigEndian:
-                    val = value.to_big_endian();
-                    break;
-                case Endianness.LittleEndian:
-                    val = value.to_little_endian();
-                    break;
-            } 
-            return val;
-        }
-
-
-        public void push_all_uint64(Enumerable<uint64?> values) {
-            values.iterate(i => push_uint64(i));
-        }
-
-        public bool equals(Enumerable<uint8> other) {
-            return this == other || matches(other, (a, b) => a == b);
-        }
-
-        public uint hash_code() {
-            return aggregate<uint>(5381, (h, b) => h * 33 + b);
-        }
-
-        public void push_int32(int32 value) {
-            var chunk = new uint8[sizeof(int32)];
-            int32 val;
-            switch (endianness) {
-                case Endianness.Native:
-                    val = value;
-                    break;
-                case Endianness.BigEndian:
-                    val = value.to_big_endian();
-                    break;
-                case Endianness.LittleEndian:
-                    val = value.to_little_endian();
-                    break;
-            }            
-            Memory.copy(chunk, &val, sizeof(int32));
-            append(Wrap.array(chunk));
-        }
-
-
-        public int32? read_int32(int index) {
-            var data = skip(index).take((int)sizeof(int32)).to_array();
-            if(data.length != sizeof(int32))
-                return null;
-            int32 value = 0;
-            int32 val = 0;
-            Memory.copy(&value, data, sizeof(int32));
-            switch (endianness) {
-                case Endianness.Native:
-                    val = value;
-                    break;
-                case Endianness.BigEndian:
-                    val = value.to_big_endian();
-                    break;
-                case Endianness.LittleEndian:
-                    val = value.to_little_endian();
-                    break;
-            } 
-            return val;           
-        }
-
-        public void push_all_int32(Enumerable<int32?> values) {
-            values.iterate(i => push_int32(i));
-        }
-
-        public void push_uint32(uint32 value) {
-            var chunk = new uint8[sizeof(uint32)];
-            uint32 val;
-            switch (endianness) {
-                case Endianness.Native:
-                    val = value;
-                    break;
-                case Endianness.BigEndian:
-                    val = value.to_big_endian();
-                    break;
-                case Endianness.LittleEndian:
-                    val = value.to_little_endian();
-                    break;
-            }            
-            Memory.copy(chunk, &val, sizeof(uint32));
-            append(Wrap.array(chunk));
-        }
-
-
-        public uint32? read_uint32(int index) {
-            var data = skip(index).take((int)sizeof(uint32)).to_array();
-            if(data.length != sizeof(uint32))
-                return null;
-            uint32 value = 0;
-            uint32 val = 0;
-            Memory.copy(&value, data, sizeof(uint32));
-            switch (endianness) {
-                case Endianness.Native:
-                    val = value;
-                    break;
-                case Endianness.BigEndian:
-                    val = value.to_big_endian();
-                    break;
-                case Endianness.LittleEndian:
-                    val = value.to_little_endian();
-                    break;
-            } 
-            return val;           
-        }
-
-        public void push_all_uint32(Enumerable<uint32?> values) {
-            values.iterate(i => push_uint32(i));
-        }
-
-        public void push_int16(int16 value) {
-            var chunk = new uint8[sizeof(int16)];
-            int16 val;
-            switch (endianness) {
-                case Endianness.Native:
-                    val = value;
-                    break;
-                case Endianness.BigEndian:
-                    val = value.to_big_endian();
-                    break;
-                case Endianness.LittleEndian:
-                    val = value.to_little_endian();
-                    break;
-            }            
-            Memory.copy(chunk, &val, sizeof(int16));
-            append(Wrap.array(chunk));
-        }
-
-
-        public int16? read_int16(int index) {
-            var data = skip(index).take((int)sizeof(int16)).to_array();
-            if(data.length != sizeof(int16))
-                return null;
-            int16 value = 0;
-            int16 val = 0;
-            Memory.copy(&value, data, sizeof(int16));
-            switch (endianness) {
-                case Endianness.Native:
-                    val = value;
-                    break;
-                case Endianness.BigEndian:
-                    val = value.to_big_endian();
-                    break;
-                case Endianness.LittleEndian:
-                    val = value.to_little_endian();
-                    break;
-            } 
-            return val;           
-        }
-
-        public void push_all_int16(Enumerable<int16?> values) {
-            values.iterate(i => push_int16(i));
-        }
-
-        public void push_uint16(uint16 value) {
-            var chunk = new uint8[sizeof(uint16)];
-            uint16 val;
-            switch (endianness) {
-                case Endianness.Native:
-                    val = value;
-                    break;
-                case Endianness.BigEndian:
-                    val = value.to_big_endian();
-                    break;
-                case Endianness.LittleEndian:
-                    val = value.to_little_endian();
-                    break;
-            }            
-            Memory.copy(chunk, &val, sizeof(uint16));
-            append(Wrap.array(chunk));
-        }
-
-        public uint16? read_uint16(int index) {
-            var data = skip(index).take((int)sizeof(uint16)).to_array();
-            if(data.length != sizeof(uint16))
-                return null;
-            uint16 value = 0;
-            uint16 val = 0;
-            Memory.copy(&value, data, sizeof(uint16));
-            switch (endianness) {
-                case Endianness.Native:
-                    val = value;
-                    break;
-                case Endianness.BigEndian:
-                    val = value.to_big_endian();
-                    break;
-                case Endianness.LittleEndian:
-                    val = value.to_little_endian();
-                    break;
-            } 
-            return val;           
-        }
-
-        public void push_all_uint16(Enumerable<uint16?> values) {
-            values.iterate(i => push_uint16(i));
-        }
-
-        public void push_int8(int8 value) {
-            var chunk = new uint8[sizeof(int8)];    
-            Memory.copy(chunk, &value, sizeof(int8));
-            append(Wrap.array(chunk));
-        }
-
-
-        public int8? read_int8(int index) {
-            var data = skip(index).take((int)sizeof(int8)).to_array();
-            if(data.length != sizeof(int8))
-                return null;
-            int8 value = 0;
-            Memory.copy(&value, data, sizeof(int8));
-            return value;           
-        }
-
-        public void push_all_int8(Enumerable<int8?> values) {
-            values.iterate(i => push_int8(i));
-        }
-
-        public void push_uint8(uint8 value) {
-            var chunk = new uint8[] { value };
-            append(Wrap.array(chunk));
-        }
-
-        public uint8? read_uint8(int index) {
-            var data = skip(index).take((int)sizeof(uint8)).to_array();
-            if(data.length != sizeof(uint8))
-                return null;
-            uint8 value = 0;
-            Memory.copy(&value, data, sizeof(uint8));
-            return value;           
-        }
-
-        public void push_all_uint8(Enumerable<uint8?> values) {
-            values.iterate(i => push_uint8(i));
-        }
-
-        public string to_escaped_string() {
-            var builder = new StringBuilder();
-            foreach (var byte in this) {
-                if(byte >= 32 && byte <= 126) {
-                    builder.append_unichar((unichar)byte);
-                }
-                else {
-                    builder.append(@"[$(byte)d]");
-                }
-            }
-            return builder.str;
-        }
-
-        public string to_raw_string(bool null_terminate = true) {
-            Enumerable<uint8> data = this;
-            if(null_terminate) {
-                data.concat(Invercargill.single<uint8>(0));
-            }
-            return (string)data.to_array();
-        }
-
-        public string to_base64() {
-            return Base64.encode(to_array());
-        }
-
-        public string to_hex() {
-            return to_string(i => i.to_string("%x"));
-        }
-
-        public Bytes to_bytes() {
-            return new Bytes(to_array());
-        }
-
-        public BinaryData slice(int start, int end) {
-            return new BinaryData.from_enumerable(skip(start).take(end-start));
-        }
-
-        public BinaryData read(int start, int length) {
-            return new BinaryData.from_enumerable(skip(start).take(length));
-        }
-
-        public bool read_in(Bytes? data, ref size_t amount) throws Error {
-            if(amount <= 0) {
-                return false;
-            }
-            if(data == null) {
-                return true;
-            }
-            if(data.length == 0) {
-                throw new BinaryDataReadError.EMPTY_READ("Encounterd zero-length data object");
-            }
-            if(data.length > amount) {
-                throw new BinaryDataReadError.BUFFER_OVERFLOW("Encountered more data than requested");
-            }
-
-            var bin = new uint8[data.length];
-            Memory.copy(bin, data.get_data(), data.length);
-            append_byte_array(bin);
-            amount -= data.length;
-            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));
-        }
-
-        public size_t write_to(void* array, size_t max_size) {
-            var data = to_array();
-            var size = max_size > data.length ? data.length : max_size;
-            Memory.copy(array, data, size);
-            return size;
-        }
-
-
-    }
-
-}

+ 33 - 1
src/lib/DataStructures/ByteBuffer.vala

@@ -1,12 +1,44 @@
 
 namespace Invercargill.DataStructures {
 
-    public class ByteBuffer : Buffer<uint8>, ReadOnlyAddressableBytes, AddressableBytes {
+    public class ByteBuffer : Buffer<uint8>, BinaryData, Equatable<Enumerable<uint8>>, Hashable, ReadOnlyAddressableBytes, AddressableBytes {
 
         public ByteBuffer(uint size) {
             base(size);
         }
 
+        public bool equals(Enumerable<uint8> other) {
+            return this == other || matches(other, (a, b) => a == b);
+        }
+
+        public uint hash_code() {
+            return aggregate<uint>(5381, (h, b) => h * 33 + b);
+        }
+
+        public ByteBuffer.from_enumerable(Enumerable<uint8> data) {
+            base.take_array(data.to_array());
+        }
+
+        public ByteBuffer.from_bytes(Bytes data) {
+            base.take_array(data.get_data());
+        }
+
+        public ByteBuffer.from_byte_array(uint8[] data) {
+            base.take_array(data);
+        }
+
+        public ByteBuffer.from_base64(string data) {
+            base.take_array(Base64.decode(data));
+        }
+
+        public ByteBuffer.from_hex(string data) {
+            var groomed = data.replace(" ", "").replace("-", "").replace(":", "").replace("0x", "");
+            base(groomed.length/2);
+            for(var i = 0; i < groomed.length/2; i++) {
+                non_error(() => this[i] = (uint8)uint.parse(groomed[i*2:(i+1)*2], 16));
+            }
+        }
+
     }
 
 }

+ 1 - 1
src/lib/Errors.vala

@@ -16,7 +16,7 @@ namespace Invercargill {
         INVALID_TYPE
     }
 
-    public errordomain BinaryDataReadError {
+    public errordomain ByteCompositionReadError {
         EMPTY_READ,
         BUFFER_OVERFLOW,
     }

+ 48 - 0
src/lib/Interfaces/BinaryData.vala

@@ -0,0 +1,48 @@
+using Invercargill.DataStructures;
+
+namespace Invercargill {
+
+    public interface BinaryData : Enumerable<uint8> {
+
+        public virtual string to_raw_string(bool null_terminate = true) {
+            Enumerable<uint8> data = this;
+            if(null_terminate) {
+                data.concat(Invercargill.single<uint8>(0));
+            }
+            return (string)data.to_array();
+        }
+
+        public virtual string to_base64() {
+            return Base64.encode(to_array());
+        }
+
+        public virtual string to_hex() {
+            return to_string(i => i.to_string("%x"));
+        }
+
+        public virtual Bytes to_bytes() {
+            return new Bytes(to_array());
+        }
+
+        public virtual ByteBuffer to_byte_buffer() {
+            return new ByteBuffer.from_enumerable(this);
+        }
+
+        public virtual BinaryData slice(int start, int end) {
+            return skip(start).take(end-start).assert_promotion<BinaryData>();
+        }
+
+        public virtual ByteBuffer read(int start, int length) {
+            return new ByteBuffer.from_enumerable(skip(start).take(length));
+        }
+
+        public virtual size_t write_to(void* array, size_t max_size) {
+            var data = to_array();
+            var size = max_size > data.length ? data.length : max_size;
+            Memory.copy(array, data, size);
+            return size;
+        }
+        
+    }
+
+}

+ 1 - 1
src/lib/Interfaces/ReadOnlyAddressableBytes.vala

@@ -9,7 +9,7 @@ namespace Invercargill {
 
 
     [GenericAccessors]
-    public interface ReadOnlyAddressableBytes : ReadOnlyAddressable<uint8> {
+    public interface ReadOnlyAddressableBytes : ReadOnlyAddressable<uint8>, Equatable<Enumerable<uint8>>, BinaryData, Hashable  {
 
         public virtual int64? get_int64(int index, Endianness endianness = Endianness.Native) throws IndexError {
             var data = get_slice(index, sizeof(int64));

+ 2 - 2
src/lib/Operators/Stringify.vala

@@ -42,8 +42,8 @@ namespace Invercargill.Operators {
         else if(type.is_a(typeof(Stringifyable))) {
             return i => ((Stringifyable)i).to_string();
         }
-        else if(type.is_a(typeof(DataStructures.BinaryData))) {
-            return i => "0x" + ((DataStructures.BinaryData)i).to_string(b => b.to_string("%x"));
+        else if(type.is_a(typeof(BinaryData))) {
+            return i => "0x" + ((BinaryData)i).to_hex();
         }
         return i => @"[$(type.name()) at 0x$(((int)i).to_string("%x"))]";
     }

+ 18 - 0
src/lib/Promotions/BinaryData.vala

@@ -0,0 +1,18 @@
+using Invercargill.Mapping;
+
+namespace Invercargill {
+
+    private class BinaryDataPromotionImplementation : Proxy<uint8>, Promotion<uint8>, BinaryData {
+
+        public Enumerable<uint8> wrap (Enumerable<uint8> enumerable) {
+            inner = enumerable;
+            return this;
+        }
+
+        public bool can_wrap (GLib.Type element_type) {
+            return element_type.is_a (typeof(uint8));
+        }
+
+    }
+
+}

+ 9 - 0
src/lib/Promotions/Registration.c

@@ -0,0 +1,9 @@
+
+#include "invercargill.h"
+
+VALA_EXTERN GType invercargill_binary_data_promotion_implementation_get_type (void) G_GNUC_CONST ;
+
+__attribute__((constructor))
+static void invercargill_register_internal_promotions() {
+    invercargill_register_promotion (INVERCARGILL_TYPE_BINARY_DATA, invercargill_binary_data_promotion_implementation_get_type());
+}

+ 7 - 7
src/lib/Wrap.vala

@@ -1,20 +1,20 @@
 using Invercargill.DataStructures;
 namespace Invercargill.Wrap {
 
-    public static Enumerable<T> array<T>(T[] input) {
+    public static ReadOnlyAddressable<T> array<T>(T[] input) {
         return new Wrappers.Array<T>(input);
     }
 
-    public static Enumerable<T> generic_array<T>(GLib.GenericArray<T> input) {
-        return new Wrappers.GenericArray<T>(input);
+    public static Lot<T> generic_array<T>(owned GLib.GenericArray<T> input) {
+        return new Wrappers.GenericArray<T>((owned)input);
     }
 
-    public static BinaryData byte_array(uint8[] input) {
-        return new BinaryData.from_byte_array(input);
+    public static ReadOnlyAddressableBytes byte_array(uint8[] input) {
+        return new DataStructures.ByteBuffer.from_byte_array(input);
     }
 
-    public static BinaryData bytes(Bytes input) {
-        return new BinaryData.from_bytes(input);
+    public static ReadOnlyAddressableBytes bytes(Bytes input) {
+        return new DataStructures.ByteBuffer.from_bytes(input);
     }
 
 }

+ 1 - 1
src/lib/Wrappers/Array.vala

@@ -1,7 +1,7 @@
 
 namespace Invercargill.Wrappers {
 
-    public class Array<T> : Enumerable<T>, Lot<T>, ReadOnlyAddressable<T> {
+    public class Array<T> : Enumerable<T>, Lot<T>, ImmutableLot<T>, ReadOnlyAddressable<T> {
 
         private T[] array;
 

+ 5 - 3
src/lib/Wrappers/GenericArray.vala

@@ -1,18 +1,20 @@
 
 namespace Invercargill.Wrappers {
 
-    public class GenericArray<T> : Enumerable<T> {
+    public class GenericArray<T> : Enumerable<T>, Lot<T> {
 
         private GLib.GenericArray<T> array;
 
-        public GenericArray(GLib.GenericArray<T> input) {
-            array = input;
+        public GenericArray(owned GLib.GenericArray<T> input) {
+            array = (owned)input;
         }
 
         public override int? peek_count() {
             return array.length;
         }
 
+        public uint length { get { return array.length; } }
+
         public override EnumerableInfo get_info() {
             return new EnumerableInfo.infer_ultimate (this, EnumerableCategory.IN_MEMORY);
         }

+ 4 - 1
src/lib/meson.build

@@ -32,6 +32,7 @@ sources += files('Iterate.vala')
 sources += files('Wrap.vala')
 sources += files('Partition.vala')
 sources += files('Composition.vala')
+sources += files('ByteComposition.vala')
 
 sources += files('Modifiers/Transform.vala')
 sources += files('Modifiers/Filter.vala')
@@ -71,6 +72,8 @@ sources += files('Promotions/Numbers/Implementations.vala')
 sources += files('Promotions/Equatables.vala')
 sources += files('Promotions/Attempts.vala')
 sources += files('Promotions/PropertyGroups.vala')
+sources += files('Promotions/BinaryData.vala')
+sources += files('Promotions/Registration.c')
 
 sources += files('Interfaces/Lot.vala')
 sources += files('Interfaces/ImmutableLot.vala')
@@ -87,10 +90,10 @@ sources += files('Interfaces/Properties.vala')
 sources += files('Interfaces/Elements.vala')
 sources += files('Interfaces/AddressableCollection.vala')
 sources += files('Interfaces/AddressableBytes.vala')
+sources += files('Interfaces/BinaryData.vala')
 
 sources += files('DataStructures/Series.vala')
 sources += files('DataStructures/Fifo.vala')
-sources += files('DataStructures/BinaryData.vala')
 sources += files('DataStructures/Vector.vala')
 sources += files('DataStructures/HashSet.vala')
 sources += files('DataStructures/Dictionary.vala')

+ 47 - 51
src/tests/Integration/BinaryData.vala → src/tests/Integration/ByteComposition.vala

@@ -1,14 +1,14 @@
 using Invercargill;
 using Invercargill.DataStructures;
 
-void binary_data_tests() {
+void byte_composition_tests() {
 
-    Test.add_func("/invercargill/structure/binary_data/read_in", () => {
+    Test.add_func("/invercargill/structure/byte_composition/read_in", () => {
 
         var large_p1 = new Bytes(range(0, 500000, 1).select<uint8>(i => (uint8)i).to_array());
         var large_p2 = new Bytes(range(0, 500000, 1).select<uint8>(i => (uint8)i).to_array());
 
-        var data = new BinaryData();
+        var data = new ByteComposition();
         size_t to_read = 1000000;
 
         assert_true(data.read_in(large_p1, ref to_read));
@@ -17,7 +17,7 @@ void binary_data_tests() {
         assert_true(to_read == 0);
     });
 
-    Test.add_func("/invercargill/structure/binary_data/endian_write_test", () => {
+    Test.add_func("/invercargill/structure/byte_composition/endian_write_test", () => {
 
         uint64 u64 = 3292849078942343;
         int64 i64 = 637292174;
@@ -39,16 +39,16 @@ void binary_data_tests() {
             0x79  // i8
         });
 
-        var bin_le = new BinaryData();
-        bin_le.endianness = BinaryData.Endianness.LittleEndian;
-        bin_le.push_uint64(u64);
-        bin_le.push_int64(i64);
-        bin_le.push_uint32(u32);
-        bin_le.push_int32(i32);
-        bin_le.push_uint16(u16);
-        bin_le.push_int16(i16);
-        bin_le.push_uint8(u8);
-        bin_le.push_int8(i8);
+        var bin_le = new ByteComposition();
+        bin_le.endianness = Endianness.LittleEndian;
+        bin_le.append_uint64(u64);
+        bin_le.append_int64(i64);
+        bin_le.append_uint32(u32);
+        bin_le.append_int32(i32);
+        bin_le.append_uint16(u16);
+        bin_le.append_int16(i16);
+        bin_le.append_uint8(u8);
+        bin_le.append_int8(i8);
 
         var expected_be = Wrap.array(new uint8[] { 
             0x00, 0x0B, 0xB2, 0xD4, 0x2B, 0xA6, 0x3A, 0x87, // u64
@@ -61,23 +61,23 @@ void binary_data_tests() {
             0x79  // i8
         });
 
-        var bin_be = new BinaryData();
-        bin_be.endianness = BinaryData.Endianness.BigEndian;
-        bin_be.push_uint64(u64);
-        bin_be.push_int64(i64);
-        bin_be.push_uint32(u32);
-        bin_be.push_int32(i32);
-        bin_be.push_uint16(u16);
-        bin_be.push_int16(i16);
-        bin_be.push_uint8(u8);
-        bin_be.push_int8(i8);
+        var bin_be = new ByteComposition();
+        bin_be.endianness = Endianness.BigEndian;
+        bin_be.append_uint64(u64);
+        bin_be.append_int64(i64);
+        bin_be.append_uint32(u32);
+        bin_be.append_int32(i32);
+        bin_be.append_uint16(u16);
+        bin_be.append_int16(i16);
+        bin_be.append_uint8(u8);
+        bin_be.append_int8(i8);
 
         assert_true(bin_le.matches(expected_le, (b1, b2) => b1 == b2));
         assert_true(bin_be.matches(expected_be, (b1, b2) => b1 == b2));
 
     });
 
-    Test.add_func("/invercargill/structure/binary_data/little_endian_read_test", () => {
+    Test.add_func("/invercargill/structure/byte_composition/little_endian_read_test", () => {
 
         uint64 u64 = 3292849078942343;
         int64 i64 = 637292174;
@@ -88,7 +88,7 @@ void binary_data_tests() {
         uint8 u8 = 253;
         int8 i8 = 121;
 
-        var le = new BinaryData.from_byte_array(new uint8[] { 
+        var le = new ByteComposition.from_byte_array(new uint8[] { 
             0x87, 0x3A, 0xA6, 0x2B, 0xD4, 0xB2, 0x0B, 0x00, // u64
             0x8E, 0x4E, 0xFC, 0x25, 0x00, 0x00, 0x00, 0x00, // i64
             0x4D, 0x13, 0x9C, 0x02, // u32
@@ -97,22 +97,20 @@ void binary_data_tests() {
             0x34, 0x0F, // i16
             0xFD, // u8
             0x79  // i8
-        });
-
-        le.endianness = BinaryData.Endianness.LittleEndian;
+        }).to_byte_buffer();
 
-        assert_true(le.read_uint64(0) == u64);
-        assert_true(le.read_int64(8) == i64);
-        assert_true(le.read_uint32(16) == u32);
-        assert_true(le.read_int32(20) == i32);
-        assert_true(le.read_uint16(24) == u16);
-        assert_true(le.read_int16(26) == i16);
-        assert_true(le.read_uint8(28) == u8);
-        assert_true(le.read_int8(29) == i8);
+        assert_true(le.get_uint64(0, Endianness.LittleEndian) == u64);
+        assert_true(le.get_int64(8, Endianness.LittleEndian) == i64);
+        assert_true(le.get_uint32(16, Endianness.LittleEndian) == u32);
+        assert_true(le.get_int32(20, Endianness.LittleEndian) == i32);
+        assert_true(le.get_uint16(24, Endianness.LittleEndian) == u16);
+        assert_true(le.get_int16(26, Endianness.LittleEndian) == i16);
+        assert_true(le.get_uint8(28) == u8);
+        assert_true(le.get_int8(29) == i8);
 
     });
 
-    Test.add_func("/invercargill/structure/binary_data/big_endian_read_test", () => {
+    Test.add_func("/invercargill/structure/byte_composition/big_endian_read_test", () => {
 
         uint64 u64 = 3292849078942343;
         int64 i64 = 637292174;
@@ -123,7 +121,7 @@ void binary_data_tests() {
         uint8 u8 = 253;
         int8 i8 = 121;
 
-        var be = new BinaryData.from_byte_array(new uint8[] { 
+        var be = new ByteComposition.from_byte_array(new uint8[] { 
             0x00, 0x0B, 0xB2, 0xD4, 0x2B, 0xA6, 0x3A, 0x87, // u64
             0x00, 0x00, 0x00, 0x00, 0x25, 0xFC, 0x4E, 0x8E, // i64
             0x02, 0x9C, 0x13, 0x4D, // u32
@@ -132,18 +130,16 @@ void binary_data_tests() {
             0x0F, 0x34, // i16
             0xFD, // u8
             0x79  // i8
-        });
-
-        be.endianness = BinaryData.Endianness.BigEndian;
-
-        assert_true(be.read_uint64(0) == u64);
-        assert_true(be.read_int64(8) == i64);
-        assert_true(be.read_uint32(16) == u32);
-        assert_true(be.read_int32(20) == i32);
-        assert_true(be.read_uint16(24) == u16);
-        assert_true(be.read_int16(26) == i16);
-        assert_true(be.read_uint8(28) == u8);
-        assert_true(be.read_int8(29) == i8);
+        }).to_byte_buffer();
+
+        assert_true(be.get_uint64(0, Endianness.BigEndian) == u64);
+        assert_true(be.get_int64(8, Endianness.BigEndian) == i64);
+        assert_true(be.get_uint32(16, Endianness.BigEndian) == u32);
+        assert_true(be.get_int32(20, Endianness.BigEndian) == i32);
+        assert_true(be.get_uint16(24, Endianness.BigEndian) == u16);
+        assert_true(be.get_int16(26, Endianness.BigEndian) == i16);
+        assert_true(be.get_uint8(28) == u8);
+        assert_true(be.get_int8(29) == i8);
 
     });
 

+ 2 - 2
src/tests/Integration/Promotion.vala

@@ -12,13 +12,13 @@ void promotion_tests() {
 
         var base64 = data.assert_promotion<BinaryData>().to_base64();
         
-        assert_cmpstr("AQAA", CompareOperator.EQ, base64);
+        assert_cmpstr("AQkH", CompareOperator.EQ, base64);
 
     });
 
     Test.add_func("/invercargill/promotions/binarydata_to_binarydata", () => {
 
-        var data = (Enumerable<uint8>)new BinaryData.from_base64("AQAA");
+        var data = (Enumerable<uint8>)new ByteBuffer.from_base64("AQkH");
         var new_data = data.assert_promotion<BinaryData>();
         
         assert_true(data == new_data);

+ 1 - 1
src/tests/TestRunner.vala

@@ -10,7 +10,7 @@ public static int main(string[] args) {
     tracker_tests();
     parallel_tests();
     first_tests();
-    binary_data_tests();
+    byte_composition_tests();
     sort_tests();
     vector_tests();
     series_tests();

+ 1 - 1
src/tests/meson.build

@@ -10,7 +10,7 @@ sources += files('Integration/Gee.vala')
 sources += files('Integration/Tracker.vala')
 sources += files('Integration/Parallel.vala')
 sources += files('Integration/Firsts.vala')
-sources += files('Integration/BinaryData.vala')
+sources += files('Integration/ByteComposition.vala')
 sources += files('Integration/Vector.vala')
 sources += files('Integration/Series.vala')
 sources += files('Integration/Arrays.vala')