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