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