// Copyright 2026 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
pub impl Show for Unit with fn output(_self, logger) {
logger.write_string("()")
}
///|
pub impl Show for Unit with fn to_string(_self) {
"()"
}
///|
pub impl Show for Bool with fn to_string(self) {
if self {
"true"
} else {
"false"
}
}
///|
pub impl Show for Int with fn to_string(self) {
Int::to_string(self)
}
///|
pub impl Show for Int64 with fn to_string(self) {
Int64::to_string(self)
}
///|
pub impl Show for UInt with fn to_string(self) {
UInt::to_string(self)
}
///|
pub impl Show for UInt64 with fn to_string(self) {
UInt64::to_string(self)
}
///|
pub impl Show for Byte with fn to_string(self) {
Byte::to_string(self)
}
///|
pub impl Show for UInt16 with fn to_string(self) {
UInt16::to_string(self)
}
///|
/// Convert a byte to a two-digit lowercase hexadecimal string.
///
/// Example:
///
/// ```mbt check
/// test {
/// inspect(Byte::to_hex(b'\x0f'), content="0f")
/// }
/// ```
pub fn Byte::to_hex(b : Byte) -> String {
fn to_hex_digit(i : Byte) -> Char {
if i < 10 {
(i + b'0').to_char()
} else {
(i + b'a' - 10).to_char()
}
}
[to_hex_digit(b / 16), to_hex_digit(b % 16)]
}
///|
test "to_hex_digit" {
inspect(Byte::to_hex(b'\xee'), content="ee")
inspect(Byte::to_hex(b'\xf3'), content="f3")
}
///|
/// Returns the escaped representation of a string.
///
/// When `quote` is true (default), the result is wrapped in double quotes
/// like a MoonBit string literal.
///
/// Escape rules:
/// - Double quote and backslash are backslash-escaped: `\"`, `\\`
/// - Common control characters use named escapes: `\n`, `\r`, `\b`, `\t`
/// - Other control characters (< U+0020) use `\u{hex}` format
/// - All other characters are displayed as-is
///
/// ```mbt check
/// test {
/// inspect("Hello \n".escape(), content="\"Hello \\n\"")
/// inspect("Hello \n".escape(quote=false), content="Hello \\n")
/// }
/// ```
pub fn String::escape(self : String, quote? : Bool = true) -> String {
let buf = StringBuilder()
self[:].escape_to(buf, quote~)
buf.to_string()
}
///|
/// Returns the escaped representation of a string view.
///
/// When `quote` is true (default), the result is wrapped in double quotes
/// like a MoonBit string literal.
///
/// Escape rules:
/// - Double quote and backslash are backslash-escaped: `\"`, `\\`
/// - Common control characters use named escapes: `\n`, `\r`, `\b`, `\t`
/// - Other control characters (< U+0020) use `\u{hex}` format
/// - All other characters are displayed as-is
///
/// ```mbt check
/// test {
/// inspect("Hello\nWorld"[:6].escape(), content="\"Hello\\n\"")
/// inspect("Hello\nWorld"[:6].escape(quote=false), content="Hello\\n")
/// }
/// ```
pub fn StringView::escape(
self : StringView,
quote? : Bool = true,
) -> StringView {
let buf = StringBuilder()
self.escape_to(buf, quote~)
buf.to_string()
}
///|
fn StringView::escape_to(
self : StringView,
logger : &Logger,
quote? : Bool = true,
) -> Unit {
if quote {
logger.write_char('"')
}
let len = self.length()
fn flush_segment(seg : Int, i : Int) {
if i > seg {
logger.write_view(self[seg:i])
}
}
for i = 0, seg = 0 {
if i >= len {
flush_segment(seg, i)
break
}
let code = self.unsafe_get(i)
match code {
'"' | '\\' as c => {
flush_segment(seg, i)
logger.write_char('\\')
logger.write_char(c.unsafe_to_char())
continue i + 1, i + 1
}
'\n' => {
flush_segment(seg, i)
logger.write_string("\\n")
continue i + 1, i + 1
}
'\r' => {
flush_segment(seg, i)
logger.write_string("\\r")
continue i + 1, i + 1
}
'\b' => {
flush_segment(seg, i)
logger.write_string("\\b")
continue i + 1, i + 1
}
'\t' => {
flush_segment(seg, i)
logger.write_string("\\t")
continue i + 1, i + 1
}
code =>
if code < ' ' {
flush_segment(seg, i)
logger.write_string("\\u{")
logger.write_string(code.to_byte().to_hex())
logger.write_char('}')
continue i + 1, i + 1
} else {
continue i + 1, seg
}
}
}
if quote {
logger.write_char('"')
}
}
///|
/// Returns the original string without escaping.
/// `Show::output` for `String` also writes the raw string through this
/// `Show::to_string` implementation.
/// Use `String::escape` when a quoted and escaped representation is needed.
/// # Examples
///
/// ```mbt check
/// test {
/// let str = "Hello \n"
/// inspect(str.to_string(), content="Hello \n")
/// inspect(str.escape(quote=true), content="\"Hello \\n\"")
/// }
/// ```
pub impl Show for String with fn to_string(self) {
self
}
///|
#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
pub impl[X : Show] Show for X?
///|
pub impl[X : Show] Show for X? with fn output(self, logger) {
match self {
None => logger.write_string("None")
Some(arg) =>
logger <+
$|Some(\{arg})
}
}
///|
#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
pub impl[T : Show, E : Show] Show for Result[T, E]
///|
pub impl[T : Show, E : Show] Show for Result[T, E] with fn output(self, logger) {
match self {
Ok(x) =>
logger <+
$|Ok(\{x})
Err(e) =>
logger <+
$|Err(\{e})
}
}
///|
#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
pub impl[X : Show] Show for FixedArray[X]
///|
pub impl[X : Show] Show for FixedArray[X] with fn output(self, logger) {
logger.write_iter(self.iter())
}
///|
#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
pub impl[X : Show] Show for Array[X]
///|
pub impl[X : Show] Show for Array[X] with fn output(self, logger) {
logger.write_iter(self.iter())
}