Skip to main content

Streamer

Struct Streamer 

Source
pub struct Streamer { /* private fields */ }
Expand description

스트리밍 변환기.

조각을 넣으면 지금 안전하게 내보낼 수 있는 만큼만 돌려준다. 경계에 걸린 마크업(**굵 에서 끊긴 것)은 안에 남겨 두고 다음 조각을 기다린다. 이것이 이 라이브러리의 핵심이다 — 완성본 변환은 이미 남들이 푼 문제고, 경계 문제는 스트리밍을 하는 한 채널과 무관하게 생긴다.

§예

use mdwire::{Channel, Streamer};

let mut s = Streamer::new(Channel::TelegramHtml);
let mut out = String::new();
// 조각 경계가 `**` 한가운데를 지나가도 반쪽으로 나가지 않는다.
out.push_str(s.push("앞말 **굵"));
out.push_str(s.push("게** 뒷말"));
out.push_str(s.finish());
assert_eq!(out, "앞말 <b>굵게</b> 뒷말");

Implementations§

Source§

impl Streamer

Source

pub fn new(channel: Channel) -> Self

Source

pub fn with_options(channel: Channel, options: Options) -> Self

옵션을 주고 만든다 — 입력 방언 따위.

Source

pub fn repairs(&self) -> Repairs

지금까지 정규화가 고친 것. finish 뒤에 보면 문서 전체의 값이다.

Source

pub fn push(&mut self, chunk: &str) -> &str

조각을 밀어 넣고, 지금 내보낼 수 있는 출력을 받는다.

돌려주는 슬라이스는 다음 호출 전까지만 유효하다. 할당을 아예 없애려면 Streamer::push_into 를 쓴다 — 둘은 같은 코드를 부른다(SPEC.md 5절).

Source

pub fn push_into(&mut self, chunk: &str, out: &mut String)

호출자 버퍼에 직접 쓴다. 정본 서명 — 조각당 할당이 0 이다.

Source

pub fn finish(&mut self) -> &str

입력이 끝났다. 남은 것을 전부 내보낸다(열린 마크업은 닫는다).

Source

pub fn finish_into(&mut self, out: &mut String)

Streamer::finish 의 무할당 판.

Source

pub fn preview(&mut self) -> &str

지금 입력이 끝났다면 확정분 뒤에 붙을 꼬리. 누적본에 이걸 붙이면 그 자리에서 보낼 수 있는 모양이다 — Streamer::close_open 과 같은 자리에 들어가지만, 붙들고 있던 것까지 그린다: 열린 강조는 닫아서(**굵 → <b>굵</b>), 표는 지금까지 온 행으로, 코드 스팬은 닫아서. 누적본을 통째로 다시 그리는 쪽(React, 텔레그램 editMessageText, 슬랙 chat.update)의 기본값이다.

꼬리는 일괄 렌더와 같은 finish 경로라 문법은 늘 맞는다. 다만 추측이다 — 끝내 안 닫힌 코드 스팬이 글자로 되돌아가는 것처럼 뒤의 조각이 모양을 바꿀 수 있다. 끝난 뒤에 마지막 미리보기와 달라졌는지는 Streamer::revised 가 알려 준다. 누적본 자체에는 넣지 않는다.

비용은 지금 열린 블록 크기에 비례한다(엔진을 복제한다). 조각마다 부르지 말고 화면을 그릴 때 부른다.

use mdwire::{Channel, Streamer};

let mut s = Streamer::new(Channel::TelegramHtml);
let mut acc = String::new();
s.push_into("앞말 **굵", &mut acc);
assert_eq!(acc, "앞말 ");                       // 확정분은 여기까지
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());                          // 마지막 화면이 곧 완성본
Source

pub fn preview_into(&mut self, out: &mut String)

Streamer::preview 를 호출자 버퍼에 덧붙인다.

Source

pub fn revised(&self) -> bool

완성본이 마지막 미리보기와 다른가 — finish 뒤에 본다. 거짓이면 마지막으로 그린 화면(누적본 + preview)이 곧 완성본이라 다시 그릴 필요가 없다. 텔레그램은 같은 내용으로 편집하면 400(“message is not modified”)을 주므로 이걸 보고 마지막 편집을 건너뛴다. 미리보기를 안 했거나 그 뒤에 조각이 더 왔으면 참이다 — 참은 “다를 수 있다” 는 뜻이다. 편집을 솎아 보내 마지막 미리보기가 마지막 조각보다 앞서면 완성본이 같아도 참이니, 그런 쪽은 마지막으로 보낸 문자열과 직접 비교한다.

Source

pub fn close_open(&self, out: &mut String)

지금까지 받은 것을 그대로 보내도 되게 만든다. 상태는 건드리지 않으므로 붙인 뒤에도 스트리밍은 이어진다.

강조는 짝이 맞을 때까지 안에 붙들려 있어 이미 균형이 맞지만, 블록의 여는 마크업(<blockquote>·<pre>·헤딩의 <b>)은 블록이 끝나기 전에 나간다 — 코드블록이 끝날 때까지 출력을 멈추면 스트리밍이 아니기 때문이다. 누적본을 중간에 채널로 보내는 쪽(토큰이 오는 대로 메시지를 편집하는 경우)은 보내기 직전에 이걸 덧붙인다. 누적본 자체에는 넣지 않는다 — 다음 조각이 이어진다.

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);          // 지금 보내도 되는 모양
assert_eq!(snapshot, "<blockquote>인용이 시작되고</blockquote>");

s.push_into("\n> 이어진다\n", &mut acc);  // 누적본은 그대로 이어진다
s.finish_into(&mut acc);
assert_eq!(acc, "<blockquote>인용이 시작되고\n이어진다</blockquote>");

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.