1use super::proto::SimpleTextOutput;
4use super::{Result, Status};
5use alloc::boxed::Box;
6use alloc::vec::Vec;
7use core::fmt::Write;
8
9#[macro_export]
10macro_rules! writeln_result {
13 [$out:ident, $($args:expr),* $(,)?] => {
14 match writeln!($out, $($args),*) {
15 _ => $out.last_result
16 }
17 }
18}
19
20#[derive(Clone, Copy)]
21pub struct OutputStream<'a> {
22 out: &'a SimpleTextOutput,
23 pub last_result: Result,
24}
25
26impl<'a> OutputStream<'a> {
27 pub fn new(out: &'a SimpleTextOutput) -> Self {
28 OutputStream { out, last_result: Ok(Status::Success) }
29 }
30}
31
32impl Write for OutputStream<'_> {
33 fn write_str(&mut self, s: &str) -> core::fmt::Result {
34 for c in s.chars() {
36 if let e @ Err(_) = self.write_char(c) {
37 return e;
38 }
39 }
40 Ok(())
41 }
42
43 fn write_char(&mut self, c: char) -> core::fmt::Result {
44 if c == '\n' {
47 self.write_char('\r')?;
48 }
49
50 let mut buffer = [0_u16; 3];
52 c.encode_utf16(&mut buffer);
53 let out = &self.out;
54 unsafe {
55 self.last_result = (out.output_string)(out, buffer.as_ptr()).into_result();
56 }
57 match self.last_result {
58 Ok(_) => Ok(()),
59 Err(_) => Err(core::fmt::Error),
60 }
61 }
62}
63
64
65pub struct Logger<'a>(pub Option<OutputStream<'a>>);
66
67impl log::Log for Logger<'_> {
68 fn log(&self, record: &log::Record) {
69 if let Some(out) = self.0 {
70 writeln!(
71 out.clone(),
72 "{} [{}] {}",
73 record.level(),
74 record.module_path().unwrap_or("<unknown>"),
75 record.args(),
76 )
77 .unwrap();
78 }
79 }
80
81 fn enabled(&self, _: &log::Metadata) -> bool {
82 true
83 }
84
85 fn flush(&self) {}
86}
87
88
89pub fn encode_c_utf16(string: &str) -> Box<[u16]> {
92 let encoded_length = 1 + string.chars().map(char::len_utf16).sum::<usize>();
94 let mut encoded = Vec::with_capacity(encoded_length);
95 encoded.extend(string.encode_utf16());
96 encoded.push(0);
97 encoded.into_boxed_slice()
98}
99
100
101#[cfg(test)]
102mod test {
103 use super::*;
104
105 #[test]
106 fn test_encode_c_utf16() {
107 assert_eq!(*encode_c_utf16(""), [0x0]);
108 assert_eq!(*encode_c_utf16("z"), [0x7a, 0x0]);
109 assert_eq!(*encode_c_utf16("\0z"), [0x0, 0x7a, 0x0]);
110
111 assert_eq!(*encode_c_utf16("Eat up 🍔!"), [
112 0x45, 0x61, 0x74, 0x20, 0x75, 0x70, 0x20, 0xd83c, 0xdf54, 0x21, 0x0,
113 ]);
114 }
115}