2013-07-29 7 views
1

Для одного сетевого протокола мне нужно иметь возможность читать гибкие куски разных типов от Source m ByteString. Комбинатор lines, который разбивает входные данные на линии, но мне нужно объединить строки чтения и фиксированное количество байтов.Как читать разные куски из кабелепровода (например, линия до LF, а затем 10 байтов)?

Мой текущий подход заключается в том, что я создаю вспомогательную функцию:

| Складывает заданную функцию на входах. Повторяйте, пока функция возвращает Left и скопируйте ее результаты в список. Когда функция возвращает Right, объединить накопленный результат (включая последний) и вернуть его, сохранить то, что осталось, используя leftover. Возвращает Nothing, если нет ввода .

chunk :: (Monad m, Monoid a) 
     => (s -> i -> Either (a, s) (a, i)) 
     -> s 
     -> Consumer i m (Maybe a) 
chunk f = loop [] 
    where 
    loop xs s = await >>= maybe (emit xs) (go xs s) 

    go xs s i = case f s i of 
     Left (x, s') -> loop (x : xs) s' 
     Right (x, l) -> leftover l >> emit (x : xs) 

    emit [] = return Nothing 
    emit xs = return (Just . mconcat . L.reverse $ xs) 
-- Note: We could use `mappend` to combine the chunks directly. But this would 
-- often get us O(n^2) complexity (like for `ByteString`s) so we keep a list of 
-- the chunks and then use `mconcat`, which can be optimized by the `Monoid`. 

С помощью этой функции я создаю конкретных потребителей:

bytes :: (Monad m) => Int -> Consumer ByteString m (Maybe ByteString) 
bytes = chunk f 
    where 
    f n bs | n' > 0  = Left (bs, n') 
      | otherwise = Right $ BS.splitAt n bs 
     where n' = n - BS.length bs 

line :: (Monad m) => Consumer ByteString m (Maybe ByteString) 
line = chunk f() 
    where 
    f _ bs = maybe (Left (bs,())) 
        (\i -> Right $ BS.splitAt (i + 1) bs) 
        (BS.findIndex (== '\n') bs) 

Есть ли лучший способ? Я полагаю, что эта проблема, должно быть, уже была решена где-то.

+0

Выглядит правильно, это очень похоже на то, как Warp разбирает заголовки запросов, хотя Warp не беспокоится о каких-либо комбинаторах более высокого уровня. –

+0

@MichaelSnoyman Спасибо, возможно, добавьте его в качестве ответа, чтобы я мог его принять. –

ответ

1

Выглядит правильно, это очень похоже на то, как Warp разбирает заголовки запросов, хотя Warp не беспокоится о каких-либо комбинаторах более высокого уровня.

 Смежные вопросы

  • Нет связанных вопросов^_^