type String { length uint32, data [u8; length], } // needs three bits to store this @exhaustive enum LogLevel { Error = 0, Warn = 1, Info = 2, Debug = 3, Trace = 4, } type LogMessage { log_level = LogLevel, log_message = String, } // This is displayed as bits sent over the wire [ 010 // INFO 00000000_00000000_00000000_00000011 // Length of the string 01001000 // H 01101001 // i 00100001 // ! ] // This is displayed as bytes in memory [ 0x3 // INFO 0xD // Length of the string 0x48 0x69 0x21 ] enum LogResult { Ok, Error, } @exhaustive protocol Logger { fn log(LogMessage) -> LogResult; fn error(String) -> LogResult; fn warn(String) -> LogResult; fn info(String) -> LogResult; fn debug(String) -> LogResult; fn trace(String) -> LogResult; fn flush() -> LogResult; } TODO argue about time being added after the fact in the logger or inplace by the loggee