///|
pub suberror OscError {
Invalid(String, Int32)
Limit(String)
} derive(Debug, Eq)
///|
pub(all) struct TimeTag {
seconds : UInt32
fraction : UInt32
} derive(Debug, Eq)
///|
pub(all) enum Argument {
I32(Int32)
F32(UInt32)
Text(String)
Blob(Bytes)
I64(Int64)
F64(UInt64)
Time(TimeTag)
Symbol(String)
Character(Int32)
Rgba(UInt32)
Midi(UInt32)
True
False
Nil
Impulse
Array(Array[Argument])
} derive(Debug, Eq)
///|
pub(all) struct Message {
address : String
arguments : Array[Argument]
} derive(Debug, Eq)
///|
pub(all) enum Packet {
Message(Message)
Bundle(TimeTag, Array[Packet])
} derive(Debug, Eq)
///|
pub(all) struct Limits {
packet_bytes : Int32
string_bytes : Int32
blob_bytes : Int32
arguments : Int32
elements : Int32
depth : Int32
} derive(Debug, Eq)
///|
pub fn Limits::default() -> Limits {
{
packet_bytes: 1048576,
string_bytes: 65536,
blob_bytes: 524288,
arguments: 4096,
elements: 4096,
depth: 32,
}
}
///|
fn Limits::validate(self : Limits) -> Unit raise OscError {
if self.packet_bytes < 16 || self.packet_bytes > 16777216 {
raise Limit("packet_bytes must be 16..16777216")
}
if self.string_bytes < 1 || self.string_bytes > self.packet_bytes {
raise Limit("string_bytes must fit packet budget")
}
if self.blob_bytes < 0 || self.blob_bytes > self.packet_bytes {
raise Limit("blob_bytes must fit packet budget")
}
if self.arguments < 0 ||
self.arguments > 65536 ||
self.elements < 0 ||
self.elements > 65536 {
raise Limit("counts must be 0..65536")
}
if self.depth < 1 || self.depth > 64 {
raise Limit("depth must be 1..64")
}
}
///|
pub fn float_argument(value : Float) -> Argument {
F32(value.reinterpret_as_uint())
}
///|
pub fn double_argument(value : Double) -> Argument {
F64(value.reinterpret_as_uint64())
}
///|
fn ascii_valid(text : String) -> Bool {
for code in text.code_units() {
if code == 0 || code > 127 {
return false
}
}
true
}
///|
pub fn validate_address(address : String) -> Unit raise OscError {
if address.length() == 0 || address[0] != 47 || !ascii_valid(address) {
raise Invalid("address must be non-NUL ASCII starting with /", 0)
}
for i in 0.. Unit raise OscError {
validate_address(address)
if address == "/" || address.has_suffix("/") || address.contains("//") {
raise Invalid("method requires nonempty path segments", 0)
}
for i in 0..
raise Invalid("pattern metacharacter in concrete method", i)
_ => ()
}
}
}
///|
pub extend OscError with Eq::{equal, not_equal}
///|
pub extend OscError with @debug.Debug::{to_repr}
///|
pub extend TimeTag with Eq::{equal, not_equal}
///|
pub extend TimeTag with @debug.Debug::{to_repr}
///|
pub extend Argument with Eq::{equal, not_equal}
///|
pub extend Argument with @debug.Debug::{to_repr}
///|
pub extend Message with Eq::{equal, not_equal}
///|
pub extend Message with @debug.Debug::{to_repr}
///|
pub extend Packet with Eq::{equal, not_equal}
///|
pub extend Packet with @debug.Debug::{to_repr}
///|
pub extend Limits with Eq::{equal, not_equal}
///|
pub extend Limits with @debug.Debug::{to_repr}