Как проанализировать объемную строку Redis RESP, используя nom? - PullRequest
0 голосов
/ 20 февраля 2019

Мне нужно использовать nom для разбора RESP запроса / ответа.Когда я перехожу к групповой строке, такой как

"$6\r\nfoobar\r\n"

или

$-1\r\n

Сначала я пишу функции для извлечения len из данных.

named!(signed_digits<&str, (Option<&str>, &str)>,
   pair!(
      opt!(alt!(tag!("+") | tag!("-"))),
      nom::digit
   )
);

named!(signed_integer<&str, i64>,
   map_res!(recognize!(signed_digits), FromStr::from_str)
);

named!(get_len_in_bulk_string<&str, i64>,
   do_parse!(
      tag!("$") >>
      len: signed_integer >>
      tag!("\r\n") >>
      (len)
   )
);

Затем я получаю необработанную строку в соответствии с len :

named!(parse_bulk_string<&str, Record>,
  map_res!(gen_len_in_bulk_string, |n|{
    if n < 0 {
        Record::BulkString(None)
    } else {
        Record::BulkString(Some(take!(n)))
    }
  })
);

Но я получаю ошибку компиляции:

Record::BulkString(Some(take!(n)))
                             ^ missing tokens in macro arguments

Какможно получить необработанную строку в соответствии с len , который был извлечен из текста ранее?Кажется, я не могу использовать take! в своем закрытии.

1 Ответ

0 голосов
/ 20 февраля 2019

Макросы, подобные take!, нуждаются в «неявном» аргументе в первой позиции: строке, которую нужно проанализировать.Обычно вы этого не видите, потому что он передается неявно, когда он вложен в другой макрос nom.

Однако здесь вы «вызываете» его напрямую, поэтому ему нужен этот аргумент явно.

Вместо этого вы можете сделать что-то вроде этого:

named!(get_bulk_string<&str, &str>,
   do_parse!(
      tag!("$") >>
      len: signed_integer >>
      string: take!(len) >>
      tag!("\r\n") >>
      (string)
   )
);

Конечно, это игнорирует случай -1, который вы можете обработать с помощью переключателя:

named!(get_bulk_string<&str, Option<&str>>,
   do_parse!(
      tag!("$") >>
      string: switch!(signed_integer,
        -1 => map!(take!(0), |_| None) |
        _ => map!(take!(42), |s| Some(s))
      ) >>
      tag!("\r\n") >>
      (string)
   )
);
...