تمرین: تجزیه Protobuf

در این تمرین، شما یک تجزیه‌کننده برای رمزگذاری باینری پروتوباف خواهید ساخت. نگران نباشید، این کار ساده‌تر از آن است که به نظر می‌رسد! این الگو نشان‌دهنده یک الگوی رایج در تجزیه داده‌ها است که شامل عبور برش‌های داده است. داده‌های اصلی هرگز کپی نمی‌شوند.

تجزیه کامل یک پیام پروتوباف نیاز به دانستن تایپ‌های این فیلدها دارد که بر اساس شماره‌های فیلد ایندکس شده‌اند. این اطلاعات معمولاً در یک فایل proto ارائه می‌شود. در این تمرین، ما این اطلاعات را به صورت عبارات match در توابعی که برای هر فیلد فراخوانی می‌شوند، کدگذاری خواهیم کرد.

ما از پروتوباف زیر استفاده خواهیم کرد:

message PhoneNumber { optional string number = 1; optional string type = 2; } message Person { optional string name = 1; optional int32 id = 2; repeated PhoneNumber phones = 3; }

یک پیام پروتوباف به عنوان مجموعه‌ای از فیلدها، یکی پس از دیگری، کدگذاری می‌شود. هر فیلد به صورت یک “تگ” به همراه مقدار آن پیاده‌سازی شده است. تگ شامل شماره فیلد (مانند 2 برای فیلد id در پیام Person) و wire type است که نحوه تعیین بار را از جریان بایت مشخص می‌کند.

اعداد، از جمله تگ، با استفاده از کدگذاری با طول متغیر به نام VARINT نمایندگی می‌شوند. خوشبختانه، تابع parse_varint برای شما تعریف شده است. کد داده شده همچنین بازخوانی‌هایی برای مدیریت فیلدهای Person و PhoneNumber و تجزیه یک پیام به مجموعه‌ای از فراخوانی‌ها به آن بازخوانی‌ها را تعریف می‌کند.

برای شما باقی‌مانده است که تابع parse_field و ویژگی ProtoMessage را برای Person و PhoneNumber پیاده‌سازی کنید.

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Speaker Notes

This slide and its sub-slides should take about 30 minutes.
  • در این تمرین موارد مختلفی وجود دارد که ممکن است تجزیه protobuf با شکست مواجه شود، مثلاً اگر بخواهید یک i32 را هنگامی که کمتر از ۴ بایت در بافر داده باقی‌مانده است، تجزیه کنید. در کد Rust معمولاً این را با استفاده از Result مدیریت می‌کنیم، اما برای سادگی در این تمرین، اگر با هرگونه خطا مواجه شویم، به جای آن که با Result برخورد کنیم، برنامه را متوقف خواهیم کرد. در روز چهارم، به بررسی دقیق‌تر مدیریت خطا در Rust خواهیم پرداخت.