Skip to main content

qubit_http/sse/
done_marker_policy.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026.
4 *    Haixing Hu, Qubit Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9//! # Done Marker Policy
10//!
11//! Defines how stream completion markers are recognized.
12//!
13//! # Author
14//!
15//! Haixing Hu
16
17use serde::{Deserialize, Serialize};
18use std::fmt;
19use std::str::FromStr;
20
21/// Policy for stream completion marker matching.
22#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
23#[serde(rename_all = "snake_case")]
24pub enum DoneMarkerPolicy {
25    /// Disable done marker recognition.
26    Disabled,
27    /// Use default marker: `[DONE]`.
28    #[default]
29    DefaultDone,
30    /// Use a custom marker string.
31    Custom(String),
32}
33
34impl fmt::Display for DoneMarkerPolicy {
35    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36        match self {
37            Self::Disabled => write!(f, "disable"),
38            Self::DefaultDone => write!(f, "default"),
39            Self::Custom(value) => write!(f, "{value}"),
40        }
41    }
42}
43
44impl FromStr for DoneMarkerPolicy {
45    type Err = parse_display::ParseError;
46
47    fn from_str(input: &str) -> Result<Self, Self::Err> {
48        let trimmed = input.trim();
49        if trimmed.eq_ignore_ascii_case("disable") {
50            return Ok(Self::Disabled);
51        }
52        if trimmed.eq_ignore_ascii_case("disabled") {
53            return Ok(Self::Disabled);
54        }
55        if trimmed.eq_ignore_ascii_case("default") {
56            return Ok(Self::DefaultDone);
57        }
58        Ok(Self::Custom(trimmed.to_string()))
59    }
60}
61
62impl DoneMarkerPolicy {
63    /// Returns whether `payload` (trimmed) signals end-of-stream per this policy.
64    ///
65    /// # Parameters
66    /// - `payload`: Typically trimmed SSE `data:` text.
67    ///
68    /// # Returns
69    /// `true` when the stream should stop emitting data chunks (e.g. `[DONE]`).
70    pub fn is_done(&self, payload: &str) -> bool {
71        match self {
72            DoneMarkerPolicy::Disabled => false,
73            DoneMarkerPolicy::DefaultDone => payload.trim() == "[DONE]",
74            DoneMarkerPolicy::Custom(marker) => payload.trim() == marker.trim(),
75        }
76    }
77}