Skip to main content

sse_parse/
lib.rs

1//! Incremental parser for Server-Sent Events (SSE) byte streams.
2//!
3//! The crate turns an ordered sequence of byte chunks into an ordered
4//! sequence of [`Event`]s, following the WHATWG HTML "interpreting an event
5//! stream" algorithm. It does no HTTP, no reconnection, and no MIME checking:
6//! those belong to the client built on top of it.
7//!
8//! Two layers:
9//!
10//! - [`SseParser`] is the sans-IO core. Feed it bytes, drain events. Every
11//!   byte sequence is a valid stream, so `feed` has no error to return, and
12//!   the time spent is linear in the bytes fed whatever the chunking.
13//!   `tests/no_panic.rs` and the fuzz target cover arbitrary bytes and
14//!   chunkings, and `tests/perf_gate.rs` bounds the scan count.
15//! - [`EventStream`] wraps any [`futures_core::Stream`] of byte chunks and
16//!   yields events. It depends on `futures-core` alone, so it runs on any
17//!   executor.
18//!
19//! ```
20//! use sse_parse::SseParser;
21//!
22//! let mut parser = SseParser::new();
23//! parser.feed(b"event: add\ndata: first\ndata: second\n\n");
24//!
25//! let event = parser.next_event().unwrap();
26//! assert_eq!(event.event, "add");
27//! assert_eq!(event.data, "first\nsecond");
28//! assert!(parser.next_event().is_none());
29//! ```
30//!
31//! # Conformance notes
32//!
33//! - Invalid UTF-8 is replaced with U+FFFD, as the Encoding Standard's UTF-8
34//!   decoder does. Parsing never reports an encoding error.
35//! - A leading `EF BB BF` byte order mark is stripped exactly once, at stream
36//!   offset 0, even when it arrives one byte per chunk. Later BOM bytes are
37//!   content.
38//! - The last event ID string is committed at every blank line, including
39//!   blocks that dispatch no event, so `id:`-only blocks still update
40//!   reconnection state.
41//! - The reconnection time (`retry`) takes effect when the field is
42//!   processed, independent of any later dispatch.
43//! - A carriage return at end of stream terminates its line.
44//!
45//! # `no_std`
46//!
47//! Disable the default `std` feature to build on `core + alloc`.
48
49#![cfg_attr(not(feature = "std"), no_std)]
50#![forbid(unsafe_code)]
51#![warn(missing_docs, rust_2018_idioms)]
52
53extern crate alloc;
54
55mod event;
56mod parser;
57mod stream;
58
59pub use event::Event;
60pub use parser::{SseParser, Stats};
61pub use stream::{Error, EventStream};