Как проанализировать объемную строку Redis RESP, используя nom?
Мне нужно использовать nom для разбора запроса / ответа RESP. Когда я прихожу к громоздкой, такой как
"$6\r\nfoobar\r\n"
или же
$-1\r\n
Сначала я пишу функции для извлечения данных из данных.
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 ответ
Макросы как 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)
)
);