1 module osc.message; 2 import osc.oscstring; 3 import osc.typetagstring; 4 import osc.addresspattern; 5 6 AddressPattern toAddressPattern(in ubyte[] b){ 7 import std.algorithm; 8 import std.conv; 9 import std.array; 10 string[] parts = b.map!(c => c.to!char) 11 .to!string[1..$] 12 .replace("\0", "") 13 .split("/"); 14 return parts.map!(p => AddressPart(p)) 15 .array; 16 } 17 unittest{ 18 const ubyte[] b = [0x2f, 0x66, 0x6f, 0x6f, 0x0, 0x0, 0x0, 0x0]; 19 import std.algorithm; 20 import std.stdio; 21 assert(b.toAddressPattern == [AddressPart("foo")]); 22 } 23 /++ 24 +/ 25 struct Message { 26 public{ 27 /// 28 this(in ubyte[] message){ 29 import std.algorithm; 30 const(ubyte)[] addressPattern = message[0..message.countUntil(0)]; 31 _addressPattern = addressPattern.toAddressPattern; 32 const(ubyte)[] remaining = message[message.countUntil(0)..$].find!"a!=0"; 33 34 assert(remaining.length%4 == 0); 35 36 const(ubyte)[] typeTagString = remaining[1..remaining.countUntil(0)]; 37 _typeTagString = TypeTagString(typeTagString); 38 import std.conv; 39 40 remaining = remaining[remaining.countUntil(0)/4*4+4..$]; 41 42 assert(remaining.length%4 == 0); 43 44 foreach (ref c; _typeTagString.content) { 45 switch (c) { 46 case 'i': 47 _args ~= remaining[0..4].dup; 48 remaining = remaining[4..$]; 49 break; 50 case 'f': 51 _args ~= remaining[0..4].dup; 52 remaining = remaining[4..$]; 53 break; 54 case 's': 55 _args ~= remaining[0..remaining.countUntil(0)/4*4+4].dup; 56 remaining = remaining[remaining.countUntil(0)/4*4+4..$]; 57 break; 58 case 'b': 59 _args ~= remaining[0..4].dup; 60 remaining = remaining[4..$]; 61 break; 62 default: 63 assert(0); 64 } 65 } 66 } 67 68 unittest{ 69 ubyte[] buffer = [0x2f, 0x66, 0x6f, 0x6f, 0x0, 0x0, 0x0, 0x0, 0x2c, 0x69, 0x69, 0x73, 0x66, 0x66, 0x0, 0x0, 0x0, 0x0, 0x3, 0xe8, 0xff, 0xff, 0xff, 0xff, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0, 0x0, 0x0, 0x3f, 0x9d, 0xf3, 0xb6, 0x40, 0xb5, 0xb2, 0x2d]; 70 auto message = Message(buffer); 71 } 72 73 /// 74 T opCast(T:ubyte[])()const{ 75 return _opCast!(T)(); 76 } 77 78 /// 79 string toString()const 80 in{ 81 assert(_args.length > 0); 82 }body{ 83 return _opCast!string(); 84 } 85 86 unittest{ 87 auto message = Message(); 88 message._addressPattern = [AddressPart("foo")]; 89 message._typeTagString = TypeTagString("s"); 90 import std.conv; 91 message._args = [OscString("hoge").to!(ubyte[])]; 92 assert(message.to!string == "/foo,shoge"); 93 } 94 95 /// 96 const(AddressPattern) addressPattern()const{ 97 return _addressPattern; 98 } 99 100 /// 101 const(TypeTagString) typeTagString()const{ 102 return _typeTagString; 103 } 104 105 /// 106 TypeTag[] typeTags()const{ 107 import std.algorithm; 108 import std.conv; 109 import std.array; 110 return _typeTagString.content.map!(c => c.to!TypeTag).array; 111 } 112 113 /// 114 T arg(T:ubyte[])(in size_t index)const{ 115 return _args[index].dup; 116 } 117 118 /// 119 T arg(T:int)(in size_t index)const{ 120 import std.bitmanip; 121 return _args[index].peek!T(); 122 } 123 124 /// 125 T arg(T:float)(in size_t index)const{ 126 import std.bitmanip; 127 return _args[index].peek!T(); 128 } 129 130 /// 131 T arg(T:string)(in size_t index)const{ 132 import std.conv:to; 133 import std.algorithm; 134 return _args[index].stripRight(0).map!(c => c.to!char).to!string; 135 } 136 137 /// 138 void addressPattern(in string str){ 139 import std.array; 140 import std.algorithm; 141 _addressPattern = str.split("/") 142 .filter!(a => a != "") 143 .map!(pattern => AddressPart(pattern)) 144 .array; 145 } 146 unittest{ 147 auto message = Message(); 148 message.addressPattern = "/foo/bar"; 149 import std.stdio; 150 import std.conv; 151 assert(message._addressPattern == [AddressPart("foo"), AddressPart("bar")]); 152 } 153 154 /// 155 void addressPattern(AddressPattern p){ 156 import std.array; 157 import std.algorithm; 158 _addressPattern = p; 159 } 160 161 /// 162 void addValue(T)(T v){ 163 import std.conv; 164 char c; 165 static if(is(T == int)){ 166 import std.bitmanip; 167 ubyte[] buffer = [0, 0, 0, 0]; 168 buffer.write!T(v, 0); 169 _args ~= buffer; 170 c = 'i'; 171 }else static if(is(T == float)){ 172 import std.bitmanip; 173 ubyte[] buffer = [0, 0, 0, 0]; 174 buffer.write!T(v, 0); 175 _args ~= buffer; 176 c = 'f'; 177 }else static if(is(T == string)){ 178 _args ~= OscString(v).to!(ubyte[]); 179 c = 's'; 180 }else static if(is(T == ubyte[])){ 181 _args ~= v; 182 c = 'b'; 183 } 184 185 _typeTagString.add(c); 186 } 187 188 /// 189 size_t size()const{ 190 import std.array; 191 return _addressPattern.size + 192 _typeTagString.size + 193 _args.join.length; 194 } 195 unittest{ 196 auto message = Message(); 197 message.addressPattern = [AddressPart("foo")]; 198 message.addValue(1000); 199 message.addValue(-1); 200 message.addValue("hello"); 201 message.addValue(1.234f); 202 message.addValue(5.678f); 203 assert(message.size == 40); 204 } 205 }//public 206 207 private{ 208 AddressPattern _addressPattern; 209 TypeTagString _typeTagString; 210 ubyte[][] _args; 211 212 T _opCast(T)()const{ 213 T b = [0, 0, 0, 0]; 214 import std.conv; 215 import std.array; 216 import std.algorithm; 217 218 auto casterArgs = _args.map!(b => b.convert!T).join; 219 auto seed = AddressPart(); 220 return _addressPattern.fold!((a, b)=> a~b)(seed) 221 .to!(T).dup 222 ~ _typeTagString.to!(T) 223 ~casterArgs; 224 } 225 226 }//private 227 }//struct Message 228 229 230 private T convert(T:ubyte[])(in ubyte[] b){ 231 return b.dup; 232 } 233 private T convert(T:string)(in ubyte[] b){ 234 import std.conv; 235 return OscString!('\0')(b).content; 236 } 237 238 unittest{ 239 auto message = Message(); 240 message.addressPattern = [AddressPart("foo")]; 241 message.addValue(1000); 242 message.addValue(-1); 243 message.addValue("hello"); 244 message.addValue(1.234f); 245 message.addValue(5.678f); 246 247 import std.conv; 248 ubyte[] a = [0x2f, 0x66, 0x6f, 0x6f, 0x0, 0x0, 0x0, 0x0, 0x2c, 0x69, 0x69, 0x73, 0x66, 0x66, 0x0, 0x0, 0x0, 0x0, 0x3, 0xe8, 0xff, 0xff, 0xff, 0xff, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0, 0x0, 0x0, 0x3f, 0x9d, 0xf3, 0xb6, 0x40, 0xb5, 0xb2, 0x2d]; 249 assert(message.to!(ubyte[]) == a); 250 } 251 252 unittest{ 253 auto ans = Message(); 254 ans.addressPattern = [AddressPart("foo")]; 255 ans.addValue(1000); 256 ans.addValue(-1); 257 ans.addValue("hello"); 258 ans.addValue(1.234f); 259 ans.addValue(5.678f); 260 261 ubyte[] a = [0x2f, 0x66, 0x6f, 0x6f, 262 0x0, 0x0, 0x0, 0x0, 263 0x2c, 0x69, 0x69, 0x73, 264 0x66, 0x66, 0x0, 0x0, 265 0x0, 0x0, 0x3, 0xe8, 266 0xff, 0xff, 0xff, 0xff, 267 0x68, 0x65, 0x6c, 0x6c, 268 0x6f, 0x0, 0x0, 0x0, 269 0x3f, 0x9d, 0xf3, 0xb6, 270 0x40, 0xb5, 0xb2, 0x2d]; 271 auto message = Message(a); 272 assert(message == ans); 273 }