pub struct Streamer { /* private fields */ }Expand description
Streaming converter.
Feed it chunks and it returns only as much as is safe to emit right now.
Markup caught on a boundary (cut off at **굵) stays inside until the next chunk arrives.
This is the core of the library — converting a finished document is a problem others have
already solved, while the boundary problem shows up on every channel as long as you stream.
§Example
use mdwire::{Channel, Streamer};
let mut s = Streamer::new(Channel::TelegramHtml);
let mut out = String::new();
// A chunk boundary inside `**` never sends half a marker.
out.push_str(s.push("앞말 **굵"));
out.push_str(s.push("게** 뒷말"));
out.push_str(s.finish());
assert_eq!(out, "앞말 <b>굵게</b> 뒷말");Implementations§
Source§impl Streamer
impl Streamer
pub fn new(channel: Channel) -> Self
Sourcepub fn with_options(channel: Channel, options: Options) -> Self
pub fn with_options(channel: Channel, options: Options) -> Self
Builds one with options.
Sourcepub fn repairs(&self) -> Repairs
pub fn repairs(&self) -> Repairs
What normalization has repaired so far. After finish, it covers the whole document.
Sourcepub fn push(&mut self, chunk: &str) -> &str
pub fn push(&mut self, chunk: &str) -> &str
Pushes a chunk and returns the output that can be emitted now.
The returned slice is valid only until the next call. To avoid allocation entirely,
use Streamer::push_into — both call the same code (SPEC.md section 5).
Sourcepub fn push_into(&mut self, chunk: &str, out: &mut String)
pub fn push_into(&mut self, chunk: &str, out: &mut String)
Writes directly into the caller’s buffer. The canonical signature — zero allocations per chunk.
Sourcepub fn finish(&mut self) -> &str
pub fn finish(&mut self) -> &str
Signals the end of input. Emits everything left (open markup is closed).
Sourcepub fn finish_into(&mut self, out: &mut String)
pub fn finish_into(&mut self, out: &mut String)
The allocation-free version of Streamer::finish.
Sourcepub fn preview(&mut self) -> &str
pub fn preview(&mut self) -> &str
The tail that would follow the final output if input ended now. Appending it to the
accumulated output gives a shape that can be sent on the spot — it goes where
Streamer::close_open goes, but also renders what is being held back: open emphasis
closed (**굵 → <b>굵</b>), tables with the rows received so far, code spans closed.
It is the default for callers that redraw the whole accumulated output (React, Telegram
editMessageText, Slack chat.update).
The tail takes the same finish path as batch rendering, so its syntax is always valid. But
it is a guess — later chunks can change the shape, for example a code span that never
closes turns back into text. After finishing, Streamer::revised tells you whether the
result differs from the last preview. Do not put it into the accumulated output itself.
The cost is proportional to the size of the currently open block (the engine is cloned). Call it when drawing the screen, not on every chunk.
use mdwire::{Channel, Streamer};
let mut s = Streamer::new(Channel::TelegramHtml);
let mut acc = String::new();
s.push_into("앞말 **굵", &mut acc);
assert_eq!(acc, "앞말 "); // final output so far
assert_eq!(format!("{acc}{}", s.preview()), "앞말 <b>굵</b>");
s.push_into("게** 끝", &mut acc);
let last = format!("{acc}{}", s.preview());
s.finish_into(&mut acc);
assert_eq!(acc, last);
assert!(!s.revised()); // the last frame is already the resultSourcepub fn preview_into(&mut self, out: &mut String)
pub fn preview_into(&mut self, out: &mut String)
Appends Streamer::preview to the caller’s buffer.
Sourcepub fn revised(&self) -> bool
pub fn revised(&self) -> bool
Whether the final output differs from the last preview — check it after finish. If
false, the last screen drawn (accumulated output + preview) already is the final output, so no
redraw is needed. Telegram returns 400 (“message is not modified”) for an edit with the same
content, so use this to skip the last edit. It is true if there was no preview or more
chunks arrived after it — true means “may differ”. If you throttle edits so the last
preview comes before the last chunk, it is true even when the final output is the same;
in that case compare against the last string you sent.
Sourcepub fn close_open(&self, out: &mut String)
pub fn close_open(&self, out: &mut String)
Makes what has been received so far safe to send as is. It does not touch the state, so streaming continues after appending it.
Emphasis is held inside until its pair arrives, so it is already balanced, but a block’s
opening markup (<blockquote>, <pre>, a heading’s <b>) goes out before the block
ends — holding output until a code block ends would not be streaming. Callers that send
the accumulated output to a channel midway (editing a message as tokens arrive) append this
right before sending. Do not put it into the accumulated output itself — the next chunk
continues from there.
use mdwire::{Channel, Streamer};
let mut s = Streamer::new(Channel::TelegramHtml);
let mut acc = String::new();
s.push_into("> 인용이 시작되고", &mut acc);
let mut snapshot = acc.clone();
s.close_open(&mut snapshot); // safe to send now
assert_eq!(snapshot, "<blockquote>인용이 시작되고</blockquote>");
s.push_into("\n> 이어진다\n", &mut acc); // the accumulated output just continues
s.finish_into(&mut acc);
assert_eq!(acc, "<blockquote>인용이 시작되고\n이어진다</blockquote>");