Rust: 使用 #[repr(C)] HList 来推断 format_args! 的静态数据中类型擦除的 fmt fn 指针。

创建于 2017-09-05  ·  3评论  ·  资料来源: rust-lang/rust

现在format_args!使用,例如ArgumentV1::new(&runtime_data, Debug::fmt) (对于{:?} ),在运行时,在运行时每个参数使用两个指针而不是一个( &runtime_data ) .

使用allow_internal_unsafe和 #44240,我们可以将(例如Debug::fmtfn指针放在(rvalue-promoted) 'static数据中,剩下的障碍是如何推断运行时数据的类型。
也就是说, Debug::fmt真的是<_ as Debug>::fmt并且_现在被推断出来,因为ArgumentV1::new的签名将它们组合在一起。 如果它们是分开的,我们需要一些新的东西。

我建议使用HList模式( struct HCons<H, T>(H, T); struct HNil; - 所以对于ABC类型的 3 个元素HCons<A, HCons<B, HCons<C, HNil>>> ),与#[repr(C)] ,这将为其提供与数组匹配的确定性布局,即这两个:

  • &'static HCons<fn(&A), HCons<fn(&B), HCons<fn(&C), HNil>>>
  • &'static [unsafe fn(*const Opaque); 3]

具有相同的表示形式,后者可以取消大小为切片。 这种从HList到数组(然后是切片)的转换可以在安全的、右值提升的HCons之上执行,这是移动fn指针的必要条件完全变成'static数据。

对于推断,我们可以简单地插入一些函数调用来匹配类型,例如推断B我们可以执行fmt::unify_fn_with_data((list.1).0, &b) ,这将使B变成typeof b .

它实际上可能是简单的有一个完全安全的“建设者”的界面,它结合了HList用格式化的HList运行时引用的,统一的类型,但我有点担心由于所有特征分派而导致的编译时间 - 在任何情况下,都应该测量影响。


A-fmt C-enhancement I-heavy T-libs

最有用的评论

对于推断,我们可以简单地插入一些函数调用来匹配类型,例如推断B我们可以执行fmt::unify_fn_with_data((list.1).0, &b) ,这将使B变成typeof b .

不知道我在想什么,它应该比那容易得多!

struct ArgMetadata<T: ?Sized> {
    // Only `unsafe` because of the later cast we do from `T` to `Opaque`.
    fmt: unsafe fn(&T, &mut Formatter<'_>) -> Result,
    // ... flags, constant string fragments, etc.
}

// TODO: maybe name this something else to emphasize repr(C)?
#[repr(C)]
struct HCons<T, Rest>(T, Rest);

// This would have to be in a "sealed module" to make it impossible to implement on more types.
trait MetadataFor<D> {
    const LEN: usize;
}
impl MetadataFor<()> for () {
    const LEN: usize = 0;
}
impl<'a, T: ?Sized, D, M> MetadataFor<HCons<&'a T, D>> for HCons<ArgMetadata<T>, M>
    where M: MetadataFor<D>
{
    const LEN: usize = M::LEN;
}

impl<'a> Arguments<'a> {
    fn new<M, D>(meta: &'a M, data: &'a D) -> Self
        where M: MetadataFor<D>
    {
        Self {
            meta: unsafe { &*(meta as *const _ as *const [ArgMetadata<Opaque>; M::LEN]) },
            data: unsafe { &*(data as *const _ as *const [&Opaque; M::LEN]) },
        }
    }
}

即我们“并行”构建两个HList ,一个具有完全不变的元数据,另一个具有对运行时数据的引用,然后所有类型推断都可以来自where fmt::Arguments::new上的子句,代码生成为零

编辑:@m-ou-se 不得不提醒我为什么我首先使用显式推理技巧:随机访问参数:失望:
(也许有足够的 const 泛型ab用法,我们可以有D: IndexHList<i, Output = T>但这需要很多努力)

所有3条评论

@rustbot声明

对于推断,我们可以简单地插入一些函数调用来匹配类型,例如推断B我们可以执行fmt::unify_fn_with_data((list.1).0, &b) ,这将使B变成typeof b .

不知道我在想什么,它应该比那容易得多!

struct ArgMetadata<T: ?Sized> {
    // Only `unsafe` because of the later cast we do from `T` to `Opaque`.
    fmt: unsafe fn(&T, &mut Formatter<'_>) -> Result,
    // ... flags, constant string fragments, etc.
}

// TODO: maybe name this something else to emphasize repr(C)?
#[repr(C)]
struct HCons<T, Rest>(T, Rest);

// This would have to be in a "sealed module" to make it impossible to implement on more types.
trait MetadataFor<D> {
    const LEN: usize;
}
impl MetadataFor<()> for () {
    const LEN: usize = 0;
}
impl<'a, T: ?Sized, D, M> MetadataFor<HCons<&'a T, D>> for HCons<ArgMetadata<T>, M>
    where M: MetadataFor<D>
{
    const LEN: usize = M::LEN;
}

impl<'a> Arguments<'a> {
    fn new<M, D>(meta: &'a M, data: &'a D) -> Self
        where M: MetadataFor<D>
    {
        Self {
            meta: unsafe { &*(meta as *const _ as *const [ArgMetadata<Opaque>; M::LEN]) },
            data: unsafe { &*(data as *const _ as *const [&Opaque; M::LEN]) },
        }
    }
}

即我们“并行”构建两个HList ,一个具有完全不变的元数据,另一个具有对运行时数据的引用,然后所有类型推断都可以来自where fmt::Arguments::new上的子句,代码生成为零

编辑:@m-ou-se 不得不提醒我为什么我首先使用显式推理技巧:随机访问参数:失望:
(也许有足够的 const 泛型ab用法,我们可以有D: IndexHList<i, Output = T>但这需要很多努力)

我有一个fmt::Arguments的新实现,通过使用包含字符串片段和任何格式选项(如果有)的新形式的“静态元数据”,它的大小只有两个指针。 (所以它现在适合一个寄存器对,这真的很好。)它也只需要每个参数堆栈上的一个指针而不是两个,正如三年前@eddyb显然已经在这个问题中建议的那样。 ^^(完全错过了这个问题,直到昨天@eddyb指出。^^')

剩下的就是更新format_args!()以生成这个新类型,这会遇到拆分对象指针和函数指针(目前在ArgumentV1 )作为函数指针的问题现在应该进入“静态元数据”。 这个问题中的建议看起来是一个很好的方法。 将尽快实施。 期待性能运行:)

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

pedrohjordao picture pedrohjordao  ·  3评论

tikue picture tikue  ·  3评论

zhendongsu picture zhendongsu  ·  3评论

SharplEr picture SharplEr  ·  3评论

Robbepop picture Robbepop  ·  3评论