1use serde::{Deserialize, Serialize};
4pub mod document;
5pub mod geometry;
6pub mod ocr;
7pub mod pillow_resize;
8pub mod progress;
9pub mod resources;
10
11#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
13#[serde(rename_all = "snake_case")]
14pub enum ErrorCode {
15 InvalidInput,
16 Unsupported,
17 Encrypted,
18 CorruptDocument,
19 ResourceLimit,
20 ModelMissing,
21 DeviceUnavailable,
22 RuntimeUnavailable,
23}
24
25impl ErrorCode {
26 pub fn as_str(&self) -> &'static str {
28 match self {
29 Self::InvalidInput => "invalid_input",
30 Self::Unsupported => "unsupported",
31 Self::Encrypted => "encrypted",
32 Self::CorruptDocument => "corrupt_document",
33 Self::ResourceLimit => "resource_limit",
34 Self::ModelMissing => "model_missing",
35 Self::DeviceUnavailable => "device_unavailable",
36 Self::RuntimeUnavailable => "runtime_unavailable",
37 }
38 }
39}
40
41#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
43pub struct Error {
44 pub code: ErrorCode,
45 pub message: String,
46}
47
48impl std::fmt::Display for Error {
49 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50 write!(formatter, "{:?}: {}", self.code, self.message)
51 }
52}
53impl std::error::Error for Error {}
54
55#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
57#[serde(try_from = "[f64; 4]", into = "[f64; 4]")]
58pub struct Rect([f64; 4]);
59
60impl TryFrom<[f64; 4]> for Rect {
61 type Error = Error;
62
63 fn try_from(value: [f64; 4]) -> Result<Self, Error> {
65 if value.iter().any(|x| !x.is_finite()) || value[2] < value[0] || value[3] < value[1] {
66 return Err(Error {
67 code: ErrorCode::InvalidInput,
68 message: "矩形坐标必须有限且有序".into(),
69 });
70 }
71 Ok(Self(value))
72 }
73}
74
75impl From<Rect> for [f64; 4] {
76 fn from(value: Rect) -> Self {
77 value.0
78 }
79}
80
81#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
83pub struct PageRange {
84 pub start: usize,
85 pub end: Option<usize>,
86}
87
88impl PageRange {
89 pub fn resolve(&self, page_count: usize) -> Result<std::ops::Range<usize>, Error> {
91 let end = self.end.unwrap_or(page_count);
92 if self.start > end || end > page_count {
93 return Err(Error {
94 code: ErrorCode::InvalidInput,
95 message: "页范围越界".into(),
96 });
97 }
98 Ok(self.start..end)
99 }
100}
101
102fn default_native_chars() -> usize {
103 20_000
104}
105#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct Limits {
108 pub max_input_bytes: usize,
109 pub max_pages: usize,
110 pub max_chars_per_page: usize,
111 #[serde(default = "default_native_chars")]
112 pub max_native_chars_per_page: usize,
113 pub max_total_chars: usize,
114 pub max_objects_per_page: usize,
115 pub max_path_segments_per_page: usize,
116 pub max_form_depth: usize,
117 pub max_links_per_page: usize,
118}
119
120impl Default for Limits {
121 fn default() -> Self {
122 Self {
123 max_input_bytes: 256 * 1024 * 1024,
124 max_pages: 10_000,
125 max_chars_per_page: 1_000_000,
126 max_native_chars_per_page: 20_000,
127 max_total_chars: 10_000_000,
128 max_objects_per_page: 200_000,
129 max_path_segments_per_page: 2_000_000,
130 max_form_depth: 32,
131 max_links_per_page: 100_000,
132 }
133 }
134}
135
136impl Limits {
137 pub fn pdf_host() -> Self {
140 Self {
141 max_input_bytes: usize::MAX,
142 max_pages: usize::MAX,
143 max_chars_per_page: usize::MAX,
144 max_native_chars_per_page: usize::MAX,
145 max_total_chars: usize::MAX,
146 max_objects_per_page: usize::MAX,
147 max_path_segments_per_page: usize::MAX,
148 max_form_depth: usize::MAX,
149 max_links_per_page: usize::MAX,
150 }
151 }
152 pub fn check_input(&self, bytes: &[u8]) -> Result<(), Error> {
154 if bytes.is_empty() {
155 return Err(Error {
156 code: ErrorCode::InvalidInput,
157 message: "输入为空".into(),
158 });
159 }
160 if bytes.len() > self.max_input_bytes {
161 return Err(Error {
162 code: ErrorCode::ResourceLimit,
163 message: "输入超过字节限制".into(),
164 });
165 }
166 Ok(())
167 }
168}