1 // Written in the D programming language.
2 
3 /**
4 The module provides tools for assembling and disassembling variable-length byte sequences that are found in different messages in the 9P / Styx protocol.
5 
6 Copyright: LightHouse Software, 2021
7 License:   $(HTTP https://github.com/aquaratixc/ESL-License, Experimental Software License 1.0).
8 Authors:   Oleg Bakharev,
9 		   Ilya Pertsev
10 */
11 module styx2000.lowlevel.vls;
12 
13 private {
14 	import styx2000.lowlevel.endianness : fromLEBytes, toLEBytes;
15 }
16 
17 /**
18 	A class that provides methods for unpacking and packing sequences of bytes into an array of unsigned bytes with an indicator of the number of elements in the sequence. 
19 	The number of elements is written in little-endian byte order at the beginning of each variable-length sequence and is the two bytes preceding the main data. 
20 	The static methods of this class allow packing and unpacking 9P / Styx protocol sequences (hereinafter we will denote such sequences as `VLS` - `Variable Length Sequences`).
21 */
22 class VariableLengthSequence
23 {
24 	/**
25 	Encode byte sequence as VLS
26     Params:
27     bytes = Array of unsigned bytes for constructing VLS.
28     
29     Typical usage:
30     ----
31     // return array [3, 0, 0, 1, 2]
32     auto vls = VariableLengthSequence.pack([0x00, 0x01, 0x02]);
33     ----
34     */
35 	static ubyte[] pack(ubyte[] bytes...)
36 	{
37 		ubyte[] rawBytes;
38 		
39 		auto fieldSize = cast(ushort) bytes.length;
40 		rawBytes ~= toLEBytes!ushort(fieldSize);
41 		rawBytes ~= bytes;
42 		
43 		return rawBytes;
44 	}
45 	
46 	/**
47 	Decode byte sequence from VLS
48     Params:
49     bytes = Array of unsigned bytes for constructing VLS.
50     Throws:
51     Exception on empty bytes array.
52     
53     Typical usage:
54     ----
55     // return array [0, 1, 2]
56     auto vls = VariableLengthSequence.unpack([3, 0, 0, 1, 2]);
57     ----
58     */
59 	static ubyte[] unpack(ubyte[] bytes...)
60 	{
61 		ubyte[] rawBytes;
62 		
63 		if (bytes.length == 0)
64 		{
65 			throw new Exception(`Wrong size of Variable Length Sequence (VLS)`);
66 		}
67 		else
68 		{
69 			auto fieldSize = fromLEBytes!ushort(bytes[0..2]);
70 			rawBytes = bytes[2..2+fieldSize];
71 		}
72 		
73 		return rawBytes;
74 	}
75 }