2012-01-28 10 views
7

Sto tentando di scrivere un Conduit utilizzando un parser attoparsec. Specificatamente, dato parseOne :: Parser T, vorrei creare un Conduit ByteString m T che applica ripetutamente il parser all'input e trasmette i risultati.Come posso trasformare un lavandino in un condotto?

attoparsec-conduit offre sinkParser per trasformare un Parser in un Sink, ma come posso trasformare questo in un SinkConduit? Quello che sto cercando è una funzione come:

conduitSink :: (Resource m) => Sink a m b -> Conduit a m b 

che alimenta più volte i dati nel Sink, producendo ogni risultato come va. Sembra che potrebbe essere scritto abbastanza facilmente come un ciclo manuale, ma mi chiedo se c'è un modo migliore.

La mancanza di questa funzione apparentemente ovvia nella libreria di conduttori mi fa pensare che potrei fare qualcosa di sbagliato; c'è un modo migliore per farlo? Il caso d'uso sta trasformando byte grezzi nella forma analizzata di un protocollo di rete basato su messaggi, da elaborare nelle fasi successive della pipeline. Ho già la direzione opposta (ad esempio Conduit T m ByteString) grazie a blaze-builder-conduit, quindi questo sembrava il modo più naturale per strutturare le cose.

risposta

6

Per questo è necessario utilizzare il sistema SequencedSink; utilizza un sink e uno stato tracciato per produrre un condotto dall'applicazione ripetuta di un produttore di lavello.

Il sink che si è creato è ottimizzato per analizzare in modo incrementale il valore uno, che sarà il risultato al termine di una sequenza di conduttori.

Dato che si desidera che questo sia parte di una conduttura di conduttura, tuttavia, e ogni pezzo del numero ByteString in arrivo potrebbe o meno corrispondere al proprio parser una o più volte, è necessario fare attenzione a ottenere un controllo più dettagliato di il processo di analisi, passando sullo stato di un parsing incompleto tra ogni applicazione del sink.

Supponendo, ad esempio, che il parser analizza [--] o [----] ecc, e T è Int che indica il numero di trattini analizzato, è necessario tenere traccia dello stato del parser come dimostrato da questo:

Input chunk Sink result - Data.Conduit.SequencedSinkResponse 
[--][---]  Emit Nothing [2, 3] 
[---][---  Emit (Just #func) [3] 
---------  Emit (Just #func) [] 
]    Emit Nothing [12] 
       Stop 

In questo caso, utilizzo lo Maybe (ByteString -> Data.Attoparsec.ByteString.Result) come stato passato; un diverso tipo di dati potrebbe essere più adatto a seconda della situazione.

Questo trattamento di flusso esplicito è necessario per mantenere la natura del gasdotto del condotto; il fatto che il conduttore del parser sia un "collo di bottiglia", in attesa di dati sufficienti per soddisfare un parser, sarebbe un notevole problema di prestazioni.

L'implementazione del sink necessario deve essere abbastanza semplice con l'interfaccia monad disponibile ResourceT.

EDIT: semplicemente applicando il lavandino in un ciclo sarebbe davvero essere la soluzione più semplice, ma avrà leggermente diverse caratteristiche di prestazioni se il parser analizza frammenti brevi che spesso finiscono ai confini di blocchi di byte.

+0

Grazie, ci provo. Questo significa che non userò affatto condoparsec-conduit?In tal caso, ci sarebbe un ostacolo all'aggiunta di un generico 'conduitParser :: (AttoparsecInput a, ResourceThrow m) => Parser a b -> Conduit a m b' alla sua interfaccia usando questa tecnica, o è una semplice omissione? – ehird

+0

@ehird, credo che sia semplicemente un'omissione; l'attuale codice 'sinkParser' suggerisce che potrebbe essere facilmente trasformato per analizzare il flusso di input più volte, poiché utilizza una tecnica simile a quella descritta sopra, ma solo che smette di consumare input dopo la prima analisi. – dflemstr

+0

In effetti, sembra che ci sia già [una richiesta di pull] (https://github.com/snoyberg/conduit/pull/11) aggiungendo 'conduitParser' ad attoparsec-enumerator; Probabilmente userò questa implementazione. Grazie per avermi informato di 'SequencedSink', a proposito; L'ho passato mentre leggevo la documentazione. – ehird

Problemi correlati