///|
/// Callback-based file/part sink. The callbacks receive parser-owned event
/// data immediately; applications can write file bytes without using the
/// in-memory `FieldCollector`.
pub struct PartSinkAdapter {
on_begin : (@model.PartMeta) -> Result[Unit, FormError]
on_data : (Bytes) -> Result[Unit, FormError]
on_end : (Int) -> Result[Unit, FormError]
on_message_end : () -> Result[Unit, FormError]
}
///|
pub fn PartSinkAdapter::new(
on_begin : (@model.PartMeta) -> Result[Unit, FormError],
on_data : (Bytes) -> Result[Unit, FormError],
on_end : (Int) -> Result[Unit, FormError],
on_message_end : () -> Result[Unit, FormError],
) -> PartSinkAdapter {
{ on_begin, on_data, on_end, on_message_end }
}
///|
fn raise_sink(result : Result[Unit, FormError]) -> Unit raise FormError {
match result {
Ok(_) => ()
Err(error) => raise error
}
}
///|
/// Deliver events to a caller-supplied sink in protocol order.
pub fn drive_events(
events : Array[@model.MultipartEvent],
sink : PartSinkAdapter,
) -> Unit raise FormError {
for event in events {
match event {
PartBegin(meta) => raise_sink((sink.on_begin)(meta))
PartData(bytes) => raise_sink((sink.on_data)(bytes))
PartEnd(index) => raise_sink((sink.on_end)(index))
MessageEnd => raise_sink((sink.on_message_end)())
}
}
}
///|
/// A transport-neutral source of already-owned body chunks. Native async and
/// framework adapters can wrap their own readers behind this callback without
/// changing the all-target core parser.
pub struct ChunkSourceAdapter {
next_chunk : () -> Result[Bytes?, FormError]
}
///|
pub fn ChunkSourceAdapter::new(
next_chunk : () -> Result[Bytes?, FormError],
) -> ChunkSourceAdapter {
{ next_chunk, }
}
///|
/// Drive a parser until the source returns `None`, then require `finish()`.
pub fn parse_from_source(
source : ChunkSourceAdapter,
parser : @parser.MultipartParser,
) -> Array[@model.MultipartEvent] raise FormError {
let events : Array[@model.MultipartEvent] = []
for ;; {
match (source.next_chunk)() {
Err(error) => raise error
Ok(Some(chunk)) => {
let parsed = parser.feed(chunk) catch {
error => raise Protocol(error~)
}
events.append(parsed)
}
Ok(None) => {
let completed = parser.finish() catch {
error => raise Protocol(error~)
}
events.append(completed)
return events
}
}
}
}