Rust: استخدم # [repr (C)] HList's لاستنتاج مؤشرات fmt fn التي تم مسحها من النوع في بيانات format_args! الثابتة.

تم إنشاؤها على ٥ سبتمبر ٢٠١٧  ·  3تعليقات  ·  مصدر: rust-lang/rust

في الوقت الحالي ، يستخدم format_args! ، على سبيل المثال ArgumentV1::new(&runtime_data, Debug::fmt) (لـ {:?} ) ، في وقت التشغيل ، باستخدام مؤشرين لكل وسيطة في وقت التشغيل بدلاً من مؤشر واحد فقط ( &runtime_data ) .

باستخدام allow_internal_unsafe و # 44240 ، يمكننا وضع مؤشرات (على سبيل المثال Debug::fmt ) fn في (rvalue -رويج) بيانات 'static ، العقبة المتبقية هي كيف لاستنتاج نوع بيانات وقت التشغيل.
وهذا يعني أن Debug::fmt هو في الحقيقة <_ as Debug>::fmt وأن _ يُستدل عليه الآن بسبب توقيع ArgumentV1::new يكتبها معًا. إذا كانا منفصلين ، فنحن بحاجة إلى شيء جديد.

أقترح استخدام النمط HList ( struct HCons<H, T>(H, T); struct HNil; - لذلك بالنسبة إلى 3 عناصر ، من الأنواع A ، B و C 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 إلى مصفوفة (ثم شريحة) أعلى ملف آمن ومروَّج لـ rvalue 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 s "بالتوازي" ، أحدهما يحتوي على بيانات وصفية ثابتة تمامًا ، والآخر به مراجع لبيانات وقت التشغيل ، وبعد ذلك يمكن أن يأتي كل نوع الاستدلال من where بند على fmt::Arguments::new ، بدون cruft كودجين!

تحرير : كان على @ m-ou-se أن يذكرني لماذا ذهبت مع خدعة الاستدلال الصريح في المقام الأول: حجج الوصول العشوائي: محبط:
(ربما مع الأدوية يكفي CONST استخدام أساسها أننا يمكن أن يكون 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 s "بالتوازي" ، أحدهما يحتوي على بيانات وصفية ثابتة تمامًا ، والآخر به مراجع لبيانات وقت التشغيل ، وبعد ذلك يمكن أن يأتي كل نوع الاستدلال من where بند على fmt::Arguments::new ، بدون cruft كودجين!

تحرير : كان على @ m-ou-se أن يذكرني لماذا ذهبت مع خدعة الاستدلال الصريح في المقام الأول: حجج الوصول العشوائي: محبط:
(ربما مع الأدوية يكفي CONST استخدام أساسها أننا يمكن أن يكون D: IndexHList<i, Output = T> ولكن هذا الكثير من الجهد)

لدي تطبيق جديد fmt::Arguments وهو عبارة عن مؤشرين فقط في الحجم باستخدام نموذج جديد من "البيانات الوصفية الثابتة التي تحتوي على كل من قطع السلسلة وأي خيارات تنسيق (إن وجدت)". (لذا فهو يناسب الآن زوجًا من السجلات ، وهو أمر رائع حقًا.) كما أنه يتطلب مؤشرًا واحدًا فقط على المكدس لكل وسيطة بدلاً من مؤشرين ، كما يبدو أن eddyb قد اقترح بالفعل منذ ثلاث سنوات في هذا العدد. ^^ (لقد فوتت هذه المشكلة تمامًا حتى أشار eddyb إليها بالأمس. ^^ ')

ما تبقى هو تحديث format_args!() لإنتاج هذا النوع الجديد بدلاً من ذلك ، والذي سيواجه مشكلة تقسيم مؤشر الكائن ومؤشر الوظيفة (وهما موجودان حاليًا معًا في ArgumentV1 ) ، كمؤشر دالة يجب أن تذهب الآن في "البيانات الوصفية الثابتة بدلاً من ذلك. يبدو الاقتراح في هذا العدد طريقة جيدة للقيام بذلك. سنحاول تنفيذ ذلك قريبا. نتطلع إلى سباق الأداء :)

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات