#rust
#Ржавчина
Вопрос:
Я пытаюсь написать анализатор пакетов, где в основном создается пакет путем анализа каждого слоя в пакете. Затем пакет содержит эти «слои» в векторе.
Код ~псевдокод ~ с ошибками компиляции выглядит примерно следующим образом —
Также добавлены комментарии ниже — для каждого шага. Я экспериментировал RefCell
, но не смог заставить это работать. По сути, проблемы перечислены в конце кода.
Основной шаблон следующий — получить объект типа слоя (каждый тип слоя вернет default
следующий объект на основе некоторого поля в текущем слое как «объект в штучной упаковке».)
Редактировать: я добавляю код, который больше, чем псевдокод — также добавлены следующие ошибки компиляции. Может быть, способ выяснить, как исправить эти ошибки, может решить проблемы.!
#[derive(Debug, Default)]
pub struct Packet<'a> {
data: Option<amp;'a [u8]>,
meta: PacketMetadata,
layers: Vec<Box<dyn Layer<'a>>>,
}
pub trait Layer<'a>: Debug {
fn from_u8<'b>(amp;mut self, bytes: amp;'b [u8]) -> Result<(Option<Box<dyn Layer>>, usize), Error>;
}
#[derive(Debug, Default)]
pub struct PacketMetadata {
timestamp: Timestamp,
inface: i8,
len: u16,
caplen: u16,
}
impl<'a> Packet<'a> {
fn from_u8(bytes: amp;'a [u8], _encap: EncapType) -> Result<Self, Error> {
let mut p = Packet::default();
let eth = ethernet::Ethernet::default();
let mut layer: RefCell<Box<dyn Layer>> = RefCell::new(Box::new(eth));
let mut res: (Option<Box<dyn Layer>>, usize);
let mut start = 0;
loop {
let mut decode_layer = layer.borrow_mut();
// process it
res = decode_layer.from_u8(amp;bytes[start..])?;
if res.0.is_none() {
break;
}
// if the layer exists, get it in a layer.
let boxed = layer.replace(res.0.unwrap());
start = res.1;
// append the layer to layers.
p.layers.push(boxed);
}
Ok(p)
}
}
Ошибки компиляции
error[E0515]: cannot return value referencing local variable `decode_layer`
--> src/lib.rs:81:9
|
68 | res = decode_layer.from_u8(amp;bytes[start..])?;
| ------------ `decode_layer` is borrowed here
...
81 | Ok(p)
| ^^^^^ returns a value referencing data owned by the current function
error[E0515]: cannot return value referencing local variable `layer`
--> src/lib.rs:81:9
|
65 | let mut decode_layer = layer.borrow_mut();
| ----- `layer` is borrowed here
...
81 | Ok(p)
| ^^^^^ returns a value referencing data owned by the current function
error: aborting due to 2 previous errors; 3 warnings emitted
Непонятно, почему возникают вышеуказанные ошибки. Я использую значения, возвращаемые вызовами. (3: предупреждения, показанные выше, можно игнорировать, они являются неиспользуемыми предупреждениями.)
Проблемы —
p.layers.last_mut
иp.layers.push
являются ли одновременные изменяемые заимствования недопустимыми. Я мог бы как-то поместить его за RefCell , но как это сделать, не ясно.- Этот код похож по шаблону на
syn::token::Token
s, однако одно основное отличие заключается в том, что тамEnum
используется(TokenTree
) . В приведенном выше примере я не могу использоватьEnum
, потому что список поддерживаемых протоколов потенциально неограничен. - Я не могу использовать
Layer
trait безTrait Objects
из-заloop
конструкции. - Шаблон можно представить как — изменяемую итерацию по контейнеру объектов признаков при обновлении самого контейнера.
- Возможно, я упускаю что-то очень простое.
Комментарии:
1. Почему вы назначаете срок службы для своей
Layer
черты, которую вы никогда не используете?2. Ваш комментарий «Я не могу использовать Enum, потому что список поддерживаемых протоколов потенциально неограничен». Почему бы и нет? Вы можете установить
enum
non_exhaustive
значение, позволяющее добавлять больше «протоколов» в будущем3. @WBuck Я не думаю, что это означает OP. Я полагаю, что намерение состоит в том, что любой конечный пользователь может решить реализовать
Layer
признак иPacket
должен работать с ним, что перечисление не может обработать.4. В качестве последнего средства я бы добавил
Enum
. Но в идеале хотелось бы избежать этого. Что касается времени жизни слоя, это остаток от какого-то эксперимента, но не думаю, что это действительно проблема в отношении этих ошибок, которые я получаю. Но в конечном итоге очистил бы его.5. На самом деле это время жизни
Layer
было проблемой!!!! :- (Аргх !!!.. Но это поможет понять, почему? 🙂 @Aplet123 не могли бы вы изменить свой комментарий на ответ? Я приму это как ответ!!
Ответ №1:
Проблема с приведенным выше кодом связана с пожизненной аннотацией на Layer
черте. Если удалить эту пожизненную аннотацию, приведенный выше код действительно компилируется с несколькими изменениями, как указано ниже —
// Layer Trait definition
pub trait Layer: Debug {
fn from_u8(amp;mut self, bytes: amp;[u8]) -> Result<(Option<Box<dyn Layer>>, usize), Error>;
}
impl<'a> Packet<'a> {
fn from_u8(bytes: amp;'a [u8], _encap: EncapType) -> Result<Self, Error> {
let mut p = Packet::default();
let eth = ethernet::Ethernet::default();
let layer: RefCell<Box<dyn Layer>> = RefCell::new(Box::new(eth));
let mut res: (Option<Box<dyn Layer>>, usize);
let mut start = 0;
loop {
{
// Do a `borrow_mut` in it's own scope, that gets dropped at the end.
let mut decode_layer = layer.borrow_mut();
res = decode_layer.from_u8(amp;bytes[start..])?;
}
if res.0.is_none() {
// This is just required to push something to the RefCell, that will get dropped anyways.
let fake_boxed = Box::new(FakeLayer {});
let boxed = layer.replace(fake_boxed);
p.layers.push(boxed);
break;
}
// if the layer exists, get it in a layer.
let boxed = layer.replace(res.0.unwrap());
start = res.1;
// append the layer to layers.
p.layers.push(boxed);
}
Ok(p)
}
}