Skip to content

Commit

Permalink
Make stream reader + writer work
Browse files Browse the repository at this point in the history
  • Loading branch information
LunaTheFoxgirl committed Oct 9, 2024
1 parent 0f00f6d commit a3817ef
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 42 deletions.
56 changes: 40 additions & 16 deletions source/numem/io/endian.d
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
module numem.io.endian;
import numem.core;
import numem.collections.vector;
import std.traits : isNumeric, isIntegral;
import std.traits : isNumeric, isIntegral, isBasicType;

@nogc nothrow:

Expand Down Expand Up @@ -56,6 +56,7 @@ private {
Is no-op if provided endianness is the same as the system's
*/
@trusted
ubyte[T.sizeof] toEndian(T)(T value, Endianess endianness) {

// Get bytes from value
Expand All @@ -79,6 +80,7 @@ ubyte[T.sizeof] toEndian(T)(T value, Endianess endianness) {
Is no-op if provided endianness is the same as the system's
*/
@system
T toEndianReinterpret(T)(T in_, Endianess endianness) {
if (endianness != NATIVE_ENDIAN) {
union tmp {
Expand All @@ -99,10 +101,40 @@ T toEndianReinterpret(T)(T in_, Endianess endianness) {
Is no-op if provided endianness is the same as the system's
*/
T fromEndian(T)(ubyte[T.sizeof] value, Endianess endianness) if (isNumeric!T) {
ubyte[] toSwap = value;
if (endianness != NATIVE_ENDIAN) toSwap.swapEndian();
return *(cast(T*)toSwap.ptr);
@trusted
T fromEndian(T)(ubyte[] value, Endianess endianness) if (isBasicType!T) {
union tmp {
T value;
ubyte[T.sizeof] bytes;
}
tmp toConvert;
toConvert.bytes = value;

if (endianness != NATIVE_ENDIAN)
swapEndian(value);

return toConvert.value;
}

/**
Gets a value from a different endianness.
Is no-op if provided endianness is the same as the system's.
*/
@system
T fromEndianReinterpret(T)(ubyte[] value, Endianess endianness) {
union tmp {
T value;
ubyte[T.sizeof] bytes;
}
tmp toConvert;
toConvert.bytes = value;

if (endianness != NATIVE_ENDIAN)
swapEndian(value);

return toConvert.value;
}

@("fromEndian: flip endianness for numeric type")
Expand All @@ -121,6 +153,7 @@ unittest {
Is no-op if provided endianness is the same as the system's.
*/
@trusted
void swapEndianInPlace(ref vector!ubyte arr, Endianess endianness) {

// Make sure to only swap if endianness doesn't match
Expand Down Expand Up @@ -156,16 +189,7 @@ unittest {
Calling this on a converted value flips the operation.
*/
@trusted
T ntoh(T)(T in_) if (isIntegral!T && T.sizeof > 1) {
static if (NATIVE_ENDIAN == Endianess.bigEndian) return in_;
else {
union tmp {
T value;
ubyte[T.sizeof] bytes;
}

tmp toConvert;
toConvert.value = in_;
return fromEndian!(T)(toConvert.bytes, Endianess.bigEndian);
}
return toEndianReinterpret(in_, Endianess.bigEndian);
}
2 changes: 1 addition & 1 deletion source/numem/io/stream/filestream.d
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ override:
return fread(buffer.ptr, 1, buffer.length, file);
}

ptrdiff_t read(ref vector!ubyte buffer, int offset, int count) {
ptrdiff_t read(ref vector!ubyte buffer, size_t offset, size_t count) {
if (offset+count >= buffer.size()) return -2;

fPosition_ += buffer.size;
Expand Down
4 changes: 2 additions & 2 deletions source/numem/io/stream/memstream.d
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,11 @@ override:
return toRead;
}

ptrdiff_t read(ref vector!ubyte buffer, int offset, int count) {
ptrdiff_t read(ref vector!ubyte buffer, size_t offset, size_t count) {
ptrdiff_t toRead = count;

// Out of range for destination
if (offset+count >= buffer.size()) return -2;
if (offset+count > buffer.length) return -2;

// Limit read to bounds
if (fPosition_+count > fLength_)
Expand Down
2 changes: 1 addition & 1 deletion source/numem/io/stream/package.d
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ class Stream {
* -1 if the stream can't be read.
* -2 if the read is out of range for the destination
*/
abstract ptrdiff_t read(ref vector!ubyte buffer, int offset, int count);
abstract ptrdiff_t read(ref vector!ubyte buffer, size_t offset, size_t count);

/**
Writes bytes from the specified buffer in to the stream
Expand Down
57 changes: 45 additions & 12 deletions source/numem/io/stream/reader.d
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,13 @@ public:
Failed reads may result in partial reads.
*/
@trusted
int read(T)(ref T val) if (isNumeric!T) {
int read(T)(ref T val) if (isBasicType!T) {
ubyte[T.sizeof] buf;
if (stream.read(buf) == T.sizeof) {
val = buf.fromEndian(endian);

// Need to slice it
ubyte[] tmp = buf[0..$];
if (stream.read(tmp) == T.sizeof) {
val = tmp.fromEndian!T(endian);
return T.sizeof;
}

Expand All @@ -50,25 +53,34 @@ public:

/// Ditto
@trusted
int read(T)(ref T val, size_t length) if (isSomeNString!T) {
if (length > val.size()) return -1;
int read(T)(ref T val, size_t length) if (isSomeSafeString!T && StringCharSize!T == 1) {
if (length > val.length)
return -1;

alias type = StringCharType!(T)*;

// TODO: Handle encoding schemes other than UTF8

// Size of a single unit
enum S_CHAR_SIZE = T.valueType.sizeof;
vector!ubyte tmp = vector!ubyte(length*S_CHAR_SIZE);
vector!ubyte tmp = vector!ubyte(length*StringCharSize!T);

// Attempt reading data
int r = stream.read(tmp, 0, length);
if (r == -1) return -1;
int r = cast(int)stream.read(tmp, 0, length);
if (r < 0)
return r;


// "Convert" the data via type punning.
val.adata[0..length] = (cast(T.valueType*)tmp.adata)[0..length];
(cast(type)val.ptr)[0..length] = (cast(type)tmp.ptr)[0..length];
return r;
}

/// Ditto
@trusted
int read(T)(ref T val, size_t length) if (isSomeVector!T) {
if (length > val.size()) return -1;
if (length > val.length)
return -1;

int r = 0;

static if (is(T.valueType == ubyte)) {
Expand All @@ -77,8 +89,10 @@ public:
T tmp;
foreach(i; 0..length) {
int ir = this.read!(T.valueType)(tmp);
if (ir == -1) return -1;
if (ir < 0)
return ir;

r += ir;
val[i] = tmp;
}
}
Expand All @@ -93,4 +107,23 @@ public:
ref Stream getStream() {
return stream;
}
}

@("Stream reader (memory buffer)")
unittest {
import numem.io.stream.memstream : MemoryStream;
alias TestReader = StreamReader!(Endianess.littleEndian);

ubyte[128] buffer;
Stream stream = new MemoryStream(buffer.ptr, buffer.length);
TestReader reader = new TestReader(stream);

// Dummy read destinations
uint dst;
nstring testStr = nstring(23);
vector!ubyte buff2 = vector!ubyte(5);

assert(reader.read(dst) == 4);
assert(reader.read(testStr, testStr.length) == testStr.length);
assert(reader.read(buff2, buff2.length) == buff2.length);
}
35 changes: 25 additions & 10 deletions source/numem/io/stream/writer.d
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,21 @@ public:
Writes value to the stream
*/
@trusted
void write(T)(T val) if (isNumeric!T) {
auto toWrite = val.toEndian(endian);
stream.write(toWrite);
}
void write(T)(T val) if (isBasicType!T) {
static if (T.sizeof > 1) {
auto toWrite = val.toEndian(endian);
stream.write(toWrite);
} else {
ubyte[1] tmp = [cast(ubyte)val];

/// Ditto
@trusted
void write(T)(T val) if (isSomeNString!T) {
stream.write(cast(ubyte[])val.toDString());
stream.write(tmp[]);
}
}

/// Ditto
@trusted
void write(T)(T val) if (is(T : string)) {
stream.write(cast(ubyte[])val);
void write(T)(T val) if (isSomeSafeString!T) {
stream.write(cast(ubyte[])val[0..$]);
}

/// Ditto
Expand All @@ -66,4 +66,19 @@ public:
ref Stream getStream() {
return stream;
}
}

@("Writing test")
unittest {
import numem.io.stream.memstream : MemoryStream;
alias TestWriter = StreamWriter!(Endianess.littleEndian);

ubyte[100] buffer;
TestWriter writer = new TestWriter(new MemoryStream(buffer.ptr, buffer.length));
foreach_reverse(i; 0..100) {
writer.write!ubyte(cast(ubyte)(i+1));
}

assert(buffer[0] == 100);
assert(buffer[99] == 1);
}

0 comments on commit a3817ef

Please sign in to comment.