Rust: format_args!의 정적 λ°μ΄ν„°μ—μ„œ μœ ν˜•μ΄ μ§€μ›Œμ§„ fmt fn 포인터λ₯Ό μœ μΆ”ν•˜λ €λ©΄ #[repr(C)] HListλ₯Ό μ‚¬μš©ν•˜μ‹­μ‹œμ˜€.

에 λ§Œλ“  2017λ…„ 09μ›” 05일  Β·  3μ½”λ©˜νŠΈ  Β·  좜처: rust-lang/rust

μ§€κΈˆ format_args! λŠ” λŸ°νƒ€μž„ μ‹œ ArgumentV1::new(&runtime_data, Debug::fmt) ( {:?} )λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€. λŸ°νƒ€μž„ μ‹œ 단 ν•˜λ‚˜κ°€ μ•„λ‹Œ μΈμˆ˜λ‹Ή μ΅œλŒ€ 두 개의 포인터λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€( &runtime_data ). .

allow_internal_unsafe 및 #44240을 μ‚¬μš©ν•˜λ©΄ (rvalue-promoted) 'static 데이터에 (예: Debug::fmt ) fn 포인터λ₯Ό λ°°μΉ˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ‚˜λ¨Έμ§€ μž₯애물은 λŸ°νƒ€μž„ λ°μ΄ν„°μ˜ μœ ν˜•μ„ μœ μΆ”ν•©λ‹ˆλ‹€.
즉, Debug::fmt λŠ” μ‹€μ œλ‘œ <_ as Debug>::fmt 이고 ArgumentV1::new 의 μ„œλͺ…이 ν•¨κ»˜ μž…λ ₯λ˜μ—ˆκΈ° λ•Œλ¬Έμ— _ κ°€ λ°”λ‘œ μ§€κΈˆ μœ μΆ”λ©λ‹ˆλ‹€. 그듀이 λΆ„λ¦¬λ˜μ–΄ μžˆλ‹€λ©΄ μš°λ¦¬λŠ” μƒˆλ‘œμš΄ 것이 ν•„μš”ν•©λ‹ˆλ‹€.

HList νŒ¨ν„΄( struct HCons<H, T>(H, T); struct HNil; - A , B 및 C μœ ν˜•μ˜ 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 μ—μ„œ λ°°μ—΄(그리고 슬라이슀)둜의 이 λ³€ν™˜μ€ fn 포인터λ₯Ό μ΄λ™ν•˜λŠ” 데 ν•„μš”ν•œ μ•ˆμ „ν•œ rvalue 승격 HCons μœ„μ—μ„œ μˆ˜ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€. '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 에 λŒ€ν•œ 절, codegen cruftκ°€ 0μž…λ‹ˆλ‹€ !

νŽΈμ§‘ : @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 에 λŒ€ν•œ 절, codegen cruftκ°€ 0μž…λ‹ˆλ‹€ !

νŽΈμ§‘ : @m-ou-seλŠ” λ‚΄κ°€ μ²˜μŒμ— λͺ…μ‹œμ  μΆ”λ‘  νŠΈλ¦­μ„ μ‚¬μš©ν•œ 이유λ₯Ό μƒκΈ°μ‹œμΌœ μ£Όμ–΄μ•Ό ν–ˆμŠ΅λ‹ˆλ‹€. μž„μ˜ μ•‘μ„ΈμŠ€ 인수: 싀망:
(μΆ©λΆ„ν•œ const μ œλ„€λ¦­ ab μ‚¬μš©μœΌλ‘œ D: IndexHList<i, Output = T> κ°€μ§ˆ 수 μžˆμ§€λ§Œ λ§Žμ€ λ…Έλ ₯이 ν•„μš”ν•©λ‹ˆλ‹€)

λ¬Έμžμ—΄ 쑰각과 λͺ¨λ“  ν˜•μ‹ 지정 μ˜΅μ…˜(μžˆλŠ” 경우)을 λͺ¨λ‘ ν¬ν•¨ν•˜λŠ” '정적 메타데이터'의 μƒˆλ‘œμš΄ ν˜•μ‹μ„ μ‚¬μš©ν•˜μ—¬ 크기가 두 포인터에 λΆˆκ³Όν•œ fmt::Arguments 의 μƒˆλ‘œμš΄ κ΅¬ν˜„μ΄ μžˆμŠ΅λ‹ˆλ‹€. (λ”°λΌμ„œ 이제 λ ˆμ§€μŠ€ν„° μŒμ— λ§žμŠ΅λ‹ˆλ‹€. 정말 μ’‹μŠ΅λ‹ˆλ‹€.) λ˜ν•œ @eddyb κ°€ 이 λ¬Έμ œμ—μ„œ 3λ…„ 전에 이미 μ œμ•ˆν•œ κ²ƒμ²˜λŸΌ μΈμˆ˜λ‹Ή μŠ€νƒμ— λŒ€ν•œ 포인터가 두 개 λŒ€μ‹  ν•˜λ‚˜λ§Œ ν•„μš”ν•©λ‹ˆλ‹€. ^^ (μ–΄μ œ @eddybκ°€ μ§€μ ν•˜κΈ° μ „κΉŒμ§€ 이 문제λ₯Ό μ™„μ „νžˆ λ†“μ³€μŠ΅λ‹ˆλ‹€. ^^')

μ—¬μ „νžˆ 남아 μžˆλŠ” 것은 format_args!() λ₯Ό μ—…λ°μ΄νŠΈν•˜μ—¬ 이 μƒˆλ‘œμš΄ μœ ν˜•μ„ λŒ€μ‹  μƒμ„±ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. 그러면 객체 포인터와 ν•¨μˆ˜ 포인터(ν˜„μž¬ ArgumentV1 ν•¨κ»˜ 있음)λ₯Ό ν•¨μˆ˜ ν¬μΈν„°λ‘œ λΆ„ν• ν•˜λŠ” λ¬Έμ œκ°€ λ°œμƒν•©λ‹ˆλ‹€. 이제 '정적 메타데이터'둜 이동해야 ν•©λ‹ˆλ‹€. 이 문제의 μ œμ•ˆμ€ κ·Έλ ‡κ²Œ ν•˜λŠ” 쒋은 방법인 것 κ°™μŠ΅λ‹ˆλ‹€. 곧 κ΅¬ν˜„ν•˜λ €κ³  ν•©λ‹ˆλ‹€. 퍼포먼슀 런이 κΈ°λŒ€λ©λ‹ˆλ‹€ :)

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰