1 module async.codec; 2 3 import std.typecons : Tuple; 4 import std.bitmanip : peek, write; 5 6 import async.container.bytebuffer; 7 8 /// 9 enum CodecType 10 { 11 TextLine, SizeGuide 12 } 13 14 /// 15 class Codec 16 { 17 /// 18 private CodecType ct; 19 private const ubyte[] magic; 20 21 /// 22 this(const CodecType ct) 23 { 24 this.ct = ct; 25 magic = null; 26 } 27 28 /// 29 this(const CodecType ct, const ushort magic) 30 { 31 this.ct = ct; 32 33 ubyte[] _magic = new ubyte[2]; 34 _magic.write!ushort(magic, 0); 35 this.magic = _magic; 36 } 37 38 /// Returns: 39 /// long: spliter position 40 /// size_t: spliter size 41 public Tuple!(long, size_t) decode(ref ByteBuffer buffer) 42 { 43 if (magic.length > 0) 44 { 45 if (buffer.length < magic.length) 46 { 47 return Tuple!(long, size_t)(-1, 0); 48 } 49 50 if (buffer[0 .. magic.length] != magic) 51 { 52 return Tuple!(long, size_t)(-2, 0); 53 } 54 } 55 56 if (ct == CodecType.TextLine) 57 { 58 long endPoint = -1; 59 60 for (size_t i = 0; i < buffer.length; i++) 61 { 62 const char ch = buffer[i]; 63 if ((ch == '\r') || (ch == '\n')) 64 { 65 endPoint = i; 66 break; 67 } 68 } 69 70 if (endPoint == -1) 71 { 72 return Tuple!(long, size_t)(-1, 0); 73 } 74 75 size_t spliterSize = 1; 76 for (size_t i = endPoint + 1; i < buffer.length; i++) 77 { 78 const char ch = buffer[i]; 79 if ((ch != '\r') && (ch != '\n')) 80 { 81 break; 82 } 83 84 spliterSize++; 85 } 86 87 return Tuple!(long, size_t)(endPoint, spliterSize); 88 } 89 else if (ct == CodecType.SizeGuide) 90 { 91 if (buffer.length < magic.length + int.sizeof) 92 { 93 return Tuple!(long, size_t)(-1, 0); 94 } 95 96 ubyte[] header = buffer[0 .. magic.length + int.sizeof]; 97 size_t size = header[magic.length .. $].peek!int(0); 98 if (buffer.length < magic.length + int.sizeof + size) 99 { 100 return Tuple!(long, size_t)(-1, 0); 101 } 102 103 return Tuple!(long, size_t)(magic.length + int.sizeof + size, 0); 104 } 105 106 assert(0); 107 } 108 }