【问题标题】:Format a `Debug` value into a utf-16 string将“调试”值格式化为 utf-16 字符串
【发布时间】:2022-12-13 12:12:38
【问题描述】:

假设我有一个实现 Debug 的类型的值,并且我想用 utf-16 对格式化该值的结果进行编码。一种方法是使用 format!,然后将 str 转换为 utf-16:

use std::fmt::Debug;

#[derive(Debug)]
pub struct User {
    name: String,
    some_ids: [u8; 16],
    // more fields, etc. Quite a few of them, actually
}

pub fn display_to_u16(user: &User) -> Vec<u16> {
    let asutf8 = format!("{user:#?}");
    asutf8.encode_utf16().collect()
}

但是不直接将结果写为 utf-16 字符串似乎很浪费——或者更准确地说是 utf-16 代码点的向量。有什么方法可以直接将值格式化为 utf-16 字符串吗?


注意:真正的要求是使用抽象的dyn Debug类型作为tracing_subscriber::field::Visit::record_debug的实现的一部分。 User 类型应仅作为示例。 “简单地”实现不同的序列化方案是不可行的。使用 Debug 特征是问题的一个组成部分。

【问题讨论】:

  • 我不确定你可以。转换开销应该非常小,除非它位于代码的真正热点内。
  • @tadman 这是在每个 tracing 事件和跨度进入/退出时短暂分配几 kB。所以它并没有那么糟糕,但我想问一下如何避免额外的混乱以防万一,避免它肯定会受到赞赏。如果可能的话,未来对这个问题的一些 ping 可能只是提醒我改变它。
  • UTF-8 到 UTF-16 只是一些字节交换,所以应该不会太糟糕。不过,我认为 Rust 非常致力于在内部使用 UTF-8,因此我不希望能够在不进行转换的情况下直接写入 UTF-16。 UTF-16 输出是否绝对必要?它往往要大得多,这对于大量的跟踪输出来说可能是个问题。
  • @tadman 是的,支持 UTF-16。输出最终出现在 JS 领域(上下文是一个 wasm 应用程序),其中字符串被编码为 UTF-16。我想在 rust 方面进行这种转换,因为通过 TextDecoder 而不是会涉及额外的 ffi 调用,这些调用成本更高(并且无论如何都在引擎盖下进行类似的转换)

标签: rust utf-16


【解决方案1】:

format!() 宏总是返回 String。然而,write!() 宏是通用版本,它接受任何实现std::fmt::Write(或std::io::Write)的东西。因此,如果有一种类型可以实现其中之一并即时编码为 UTF16,那么那将是您最好的选择。

我快速浏览了一下,没有找到提供此功能的第 3 方板条箱,但自己实现起来很容易:

use std::fmt::{Error, Write};

struct Utf16Writer(Vec<u16>);

impl Write for Utf16Writer {
    fn write_str(&mut self, s: &str) -> Result<(), Error> {
        Ok(self.0.extend(s.encode_utf16()))
    }
    
    fn write_char(&mut self, c: char) -> Result<(), Error> {
        Ok(self.0.extend(c.encode_utf16(&mut [0; 2]).iter()))
    }
}

然后你可以像这样使用它:

use std::fmt::{Debug, Write};

pub fn display_to_u16(user: &User) -> Vec<u16> {
    let mut writer = Utf16Writer(Vec::new());
    write!(writer, "{user:#?}").unwrap();
    writer.0
}

您可以自己评估性能,但我怀疑这会使它更快(尽管它可能使用更少的内存)。中间调用可能需要将相关数据编码为 UTF8(如果尚未编码),以便将其作为 str 传递,因此您并没有真正节省任何编码步骤。

【讨论】:

  • 它确实节省了一些分配,所以非常感谢这个版本!
猜你喜欢
  • 2012-10-09
  • 1970-01-01
  • 2014-01-18
  • 2012-03-30
  • 2010-09-21
  • 2014-02-05
  • 1970-01-01
  • 1970-01-01
  • 2011-09-06
相关资源
最近更新 更多