Skip to content

Instantly share code, notes, and snippets.

@MrSmith33
Last active August 29, 2015 14:15
Show Gist options
  • Save MrSmith33/c3bec83f624575f5ac2a to your computer and use it in GitHub Desktop.
Save MrSmith33/c3bec83f624575f5ac2a to your computer and use it in GitHub Desktop.
private import std.string : format;
private import std.traits;
private import std.typecons : Flag;
private import std.range : isInputRange, isOutputRange, ElementType;
private import std.typecons : isTuple;
/// Encodes value E into output range sink.
/// Returns number of bytes written to sink.
size_t encodeCbor(R, E)(auto ref R sink, E value)
if(isOutputRange!(R, ubyte))
{
return encodeCborArray(sink, value);
}
/// Encodes array of any items or a tuple as cbor array.
size_t encodeCborArray(R, E)(auto ref R sink, E value)
if(isOutputRange!(R, ubyte) &&
(isInputRange!E || isArray!E || isTuple!E))
{
foreach(item; value)
encodeCbor(sink, item);
return 0;
}
/// Encodes structs and classes as cbor array.
size_t encodeCborArray(R, A)(auto ref R sink, A aggregate)
if(isOutputRange!(R, ubyte) &&
(is(A == struct) || is(A == class)) &&
!isTuple!A)
{
return encodeCborAggregate!(Flag!"WithFieldName".no)(sink, aggregate);
}
/// Encodes classes and structs. If withFieldName is yes, than value is encoded as map.
/// If withFieldName is no, then value is encoded as an array.
size_t encodeCborAggregate(Flag!"WithFieldName" withFieldName, R, A)(auto ref R sink, auto ref A aggregate)
if (isOutputRange!(R, ubyte) && (is(A == struct) || is(A == class)))
{
size_t size;
size += numEncodableMembers!A;
foreach(i, member; aggregate.tupleof)
{
static if (__traits(compiles, { encodeCbor(sink, member); }))
{
static if (withFieldName)
size += encodeCborString(sink, __traits(identifier, aggregate.tupleof[i]));
size += encodeCbor(sink, member);
}
}
return size;
}
private template isEncodedField(T)
{
enum isEncodedField = __traits(compiles, { encodeCbor((ubyte[]).init, T.init); });
}
/// Returns a number of aggregate members that will be encoded by cbor-d.
template numEncodableMembers(alias T)
{
enum numEncodableMembers = numEncodableMembersImpl!(T.tupleof);
}
private template numEncodableMembersImpl(members ...)
{
static if (members.length == 0)
enum numEncodableMembersImpl = 0;
else
enum numEncodableMembersImpl =
cast(int)__traits(compiles, { encodeCbor(cast(ubyte[])null, members[0].init); }) +
numEncodableMembersImpl!(members[1..$]);
}
unittest
{
import std.array : Appender;
Appender!(ubyte[]) a;
class Class
{
Class[] groups;
}
size_t b = __traits(compiles, { encodeCbor(cast(ubyte[])null, members[0].init); });
encodeCborArray(a, Class[].init);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment