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 }