systemprompt_provider_contracts/documents/
format.rs1use std::fmt;
7use std::str::FromStr;
8
9use schemars::JsonSchema;
10use serde::{Deserialize, Serialize};
11
12#[derive(
13 Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
14)]
15#[serde(rename_all = "snake_case")]
16pub enum DocumentFormat {
17 Docx,
18 Xlsx,
19 Pptx,
20 Odt,
21 Ods,
22 Odp,
23 Html,
24 Markdown,
25 Text,
26}
27
28#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
29#[error("unknown document format `{value}`")]
30pub struct UnknownDocumentFormat {
31 pub value: String,
32}
33
34impl DocumentFormat {
35 pub const ALL: [Self; 9] = [
36 Self::Docx,
37 Self::Xlsx,
38 Self::Pptx,
39 Self::Odt,
40 Self::Ods,
41 Self::Odp,
42 Self::Html,
43 Self::Markdown,
44 Self::Text,
45 ];
46
47 #[must_use]
48 pub const fn as_str(self) -> &'static str {
49 match self {
50 Self::Docx => "docx",
51 Self::Xlsx => "xlsx",
52 Self::Pptx => "pptx",
53 Self::Odt => "odt",
54 Self::Ods => "ods",
55 Self::Odp => "odp",
56 Self::Html => "html",
57 Self::Markdown => "markdown",
58 Self::Text => "text",
59 }
60 }
61
62 #[must_use]
63 pub const fn mime_type(self) -> &'static str {
64 match self {
65 Self::Docx => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
66 Self::Xlsx => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
67 Self::Pptx => {
68 "application/vnd.openxmlformats-officedocument.presentationml.presentation"
69 },
70 Self::Odt => "application/vnd.oasis.opendocument.text",
71 Self::Ods => "application/vnd.oasis.opendocument.spreadsheet",
72 Self::Odp => "application/vnd.oasis.opendocument.presentation",
73 Self::Html => "text/html",
74 Self::Markdown => "text/markdown",
75 Self::Text => "text/plain",
76 }
77 }
78
79 #[must_use]
80 pub const fn extension(self) -> &'static str {
81 match self {
82 Self::Markdown => "md",
83 Self::Text => "txt",
84 other => other.as_str(),
85 }
86 }
87
88 #[must_use]
89 pub fn from_extension(extension: &str) -> Option<Self> {
90 let lower = extension.trim_start_matches('.').to_ascii_lowercase();
91 match lower.as_str() {
92 "htm" => Some(Self::Html),
93 "md" | "markdown" => Some(Self::Markdown),
94 "txt" | "text" => Some(Self::Text),
95 other => Self::ALL.into_iter().find(|f| f.as_str() == other),
96 }
97 }
98
99 #[must_use]
100 pub const fn is_office(self) -> bool {
101 matches!(
102 self,
103 Self::Docx | Self::Xlsx | Self::Pptx | Self::Odt | Self::Ods | Self::Odp
104 )
105 }
106
107 #[must_use]
108 pub const fn supports_three_way_merge(self) -> bool {
109 matches!(self, Self::Html | Self::Markdown | Self::Text)
110 }
111}
112
113impl fmt::Display for DocumentFormat {
114 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115 f.write_str(self.as_str())
116 }
117}
118
119impl FromStr for DocumentFormat {
120 type Err = UnknownDocumentFormat;
121
122 fn from_str(s: &str) -> Result<Self, Self::Err> {
123 Self::ALL
124 .into_iter()
125 .find(|f| f.as_str() == s)
126 .ok_or_else(|| UnknownDocumentFormat {
127 value: s.to_owned(),
128 })
129 }
130}