1 module osc.bundle;
2 import std.datetime;
3 import osc.oscstring;
4 import osc.timetag;
5 import osc.message;
6 
7 /++
8 +/
9 struct Bundle {
10     public{
11         ///
12         this(BundleElement[] bundleElements, in SysTime utcSysTime, in bool isImmediately = false){
13             _timeTag = TimeTag(utcSysTime, isImmediately);
14             _elements = bundleElements;
15         }
16         
17         ///
18         this(in ubyte[] bundle){
19             _timeTag = TimeTag(bundle[8..16]);
20             
21             ubyte[] elements = bundle[16..$].dup;
22             do{
23                 import std.bitmanip;
24                 size_t size_n = elements[0..4].peek!uint;
25                 
26                 _elements ~= BundleElement(elements[0..4+size_n]);
27                 elements = elements[4+size_n..$];
28             }while(elements != []);
29         }
30         unittest{
31             ubyte[] buffer = [35, 98, 117, 110, 100, 108, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 32, 47, 111, 115, 99, 105, 108, 108, 97, 116, 111, 114, 47, 52, 47, 102, 114, 101, 113, 117, 101, 110, 99, 121, 0, 44, 102, 0, 0, 67, 222, 0, 0];
32             auto bundle = Bundle(buffer);
33         }
34         
35         ///
36         string toString()const{
37             return _opCast!string;
38         }
39         
40         ///
41         ubyte[] opCast(T:ubyte[])()const{
42             return _opCast!T;
43         }
44         
45         ///
46         size_t size()const{
47             import std.conv;
48             import std.algorithm;
49             return _header.size + 
50                    _timeTag.size + 
51                    _elements.map!(e => e.size)
52                                   .sum;
53         }
54         
55         ///
56         const(BundleElement)[] elements()const{
57             return _elements[];
58         }
59     }//public
60 
61     private{
62         immutable OscString!('\0') _header = OscString("#bundle");
63         const TimeTag _timeTag;
64         BundleElement[] _elements;
65         
66         T _opCast(T)()const{
67             import std.conv;
68             import std.algorithm;
69             return _header.to!T ~
70                    _timeTag.to!T ~
71                    _elements.map!(e => e.to!T)
72                                   .reduce!"a~b";
73         }
74     }//private
75 }//struct Bundle
76 
77 unittest{
78     ubyte[] b = [35, 98, 117, 110, 100, 108, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 32, 47, 111, 115, 99, 105, 108, 108, 97, 116, 111, 114, 47, 52, 47, 102, 114, 101, 113, 117, 101, 110, 99, 121, 0, 44, 102, 0, 0, 67, 222, 0, 0];
79     auto bundle = Bundle(b);
80     
81     import osc.addresspattern;
82     assert(bundle.elements[0].message.addressPattern == [AddressPart("oscillator"), AddressPart("4"), AddressPart("frequency")]);
83     import osc.typetagstring;
84     assert(bundle.elements[0].message.typeTagString == TypeTagString("f"));
85     import std.conv;
86     assert(bundle.elements[0].message.arg!float(0) == 444.0f);
87 }
88 
89 /++
90 +/
91 struct BundleElement {
92     public{
93         ///
94         this(in Message message){
95             _hasMessage = true;
96             _message = message;
97             _size = message.size;
98             
99             import std.conv;
100             import std.bitmanip;
101             ubyte[] buffer = [0, 0, 0, 0];
102             buffer.write!int(message.size.to!int, 0);
103             _sizeUbyte = buffer;
104         }
105         
106         ///
107         this(in Bundle bundle){
108             _hasBundle = true;
109             _bundle = bundle;
110             _size = bundle.size;
111             
112             import std.conv;
113             import std.bitmanip;
114             ubyte[] buffer = [0, 0, 0, 0];
115             buffer.write!int(bundle.size.to!int, 0);
116             _sizeUbyte = buffer;
117         }
118         
119         ///
120         this(in ubyte[] bundleElement){
121             _size = bundleElement.length-4;
122             
123             _hasBundle = bundleElement[4] == 0x23;
124             _hasMessage = bundleElement[4] != 0x23;
125             
126             if(_hasBundle){
127                 _bundle = Bundle(bundleElement[4..$]);
128             }
129             if(_hasMessage){
130                 _message = Message(bundleElement[4..$]);
131             }
132         }
133         
134         ///
135         string toString()const{
136             import std.conv:to;
137             import std.algorithm;
138             if(_hasMessage){
139                 return _size.to!string ~ _message.to!string;
140             }else if(_hasBundle){
141                 return _size.to!string ~ _bundle.to!string;
142             }else{
143                 return "";
144             }
145         }
146         
147         ///
148         ubyte[] opCast(T:ubyte[])()const{
149             import std.conv;
150             if(_hasMessage){
151                 return _sizeUbyte ~ _message.to!(ubyte[]);
152             }else if(_hasBundle){
153                 return _sizeUbyte ~ _bundle.to!(ubyte[]);
154             }else{
155                 return [];
156             }
157         }
158         
159         size_t size()const{
160             return _size;
161         }
162         
163         ///
164         const(Message) message()const{
165             return _message;
166         }
167         
168         ///
169         const(Bundle) bundle()const{
170             return _bundle;
171         }
172         
173         ///
174         bool hasMessage()const{
175             return _hasMessage;
176         }
177         
178         ///
179         bool hasBundle()const{
180             return _hasBundle;
181         }
182     }//public
183 
184     private{
185         size_t _size;
186         ubyte[] _sizeUbyte;
187         bool _hasMessage = true;
188         bool _hasBundle = true;
189         const Message _message;
190         const Bundle _bundle;
191     }//private
192 }//struct BundleElement
193 unittest{
194     ubyte[] bundle = [35, 98, 117, 110, 100, 108, 101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 32, 47, 111, 115, 99, 105, 108, 108, 97, 116, 111, 114, 47, 52, 47, 102, 114, 101, 113, 117, 101, 110, 99, 121, 0, 44, 102, 0, 0, 67, 222, 0, 0];
195     ubyte[] size = [0, 0, 0, 0];
196     import std.bitmanip;
197     import std.conv;
198     size.write!int(bundle.length.to!int, 0);
199     auto bundleElement = BundleElement(size ~ bundle);
200     
201     import osc.addresspattern;
202     assert(bundleElement.bundle.elements[0].message.addressPattern == [AddressPart("oscillator"), AddressPart("4"), AddressPart("frequency")]);
203 }