1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/*******************************************************************************
*
* Copyright (c) 2026 Haixing Hu.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0.
*
******************************************************************************/
//! Top-level MIME detector interface.
use std::fmt::Debug;
use std::path::Path;
use std::sync::Arc;
use qubit_io::ReadSeek;
use crate::{
MimeDetectionPolicy,
MimeResult,
};
/// Detects MIME types from filenames and content.
pub trait MimeDetector: Debug + Send + Sync {
/// Detects a MIME type from a filename.
///
/// # Parameters
/// - `filename`: File path or basename.
///
/// # Returns
/// First matching MIME type name, or `None`.
fn detect_by_filename(&self, filename: &str) -> Option<String>;
/// Detects a MIME type from content bytes.
///
/// # Parameters
/// - `content`: Content bytes to inspect.
///
/// # Returns
/// First matching MIME type name, or `None`.
fn detect_by_content(&self, content: &[u8]) -> Option<String>;
/// Detects a MIME type from content bytes and an optional filename.
///
/// # Parameters
/// - `content`: Content bytes to inspect.
/// - `filename`: Optional file path or basename.
/// - `policy`: Strategy for resolving filename and content results.
///
/// # Returns
/// Selected MIME type name, or `None`.
fn detect(
&self,
content: &[u8],
filename: Option<&str>,
policy: MimeDetectionPolicy,
) -> Option<String>;
/// Detects a MIME type from a seekable reader without consuming its position.
///
/// # Parameters
/// - `reader`: Reader to inspect. The original stream position is restored.
/// - `filename`: Optional path or basename used for filename detection.
/// - `policy`: Strategy for resolving filename and content results.
///
/// # Returns
/// Selected MIME type name, or `None`.
///
/// # Errors
/// Returns [`MimeError::Io`](crate::MimeError::Io) when reading or seeking fails.
fn detect_reader(
&self,
reader: &mut dyn ReadSeek,
filename: Option<&str>,
policy: MimeDetectionPolicy,
) -> MimeResult<Option<String>>;
/// Detects a MIME type from a local file.
///
/// # Parameters
/// - `file`: Local file path.
/// - `policy`: Strategy for resolving filename and content results.
///
/// # Returns
/// Selected MIME type name, or `None`.
///
/// # Errors
/// Returns [`MimeError::Io`](crate::MimeError::Io) when the file cannot be opened or read, or
/// another [`MimeError`](crate::MimeError) when a detector backend fails.
fn detect_file(&self, file: &Path, policy: MimeDetectionPolicy) -> MimeResult<Option<String>>;
}
impl MimeDetector for Box<dyn MimeDetector> {
/// Delegates filename detection to the boxed detector.
fn detect_by_filename(&self, filename: &str) -> Option<String> {
self.as_ref().detect_by_filename(filename)
}
/// Delegates content detection to the boxed detector.
fn detect_by_content(&self, content: &[u8]) -> Option<String> {
self.as_ref().detect_by_content(content)
}
/// Delegates combined detection to the boxed detector.
fn detect(
&self,
content: &[u8],
filename: Option<&str>,
policy: MimeDetectionPolicy,
) -> Option<String> {
self.as_ref().detect(content, filename, policy)
}
/// Delegates reader detection to the boxed detector.
fn detect_reader(
&self,
reader: &mut dyn ReadSeek,
filename: Option<&str>,
policy: MimeDetectionPolicy,
) -> MimeResult<Option<String>> {
self.as_ref().detect_reader(reader, filename, policy)
}
/// Delegates file detection to the boxed detector.
fn detect_file(&self, file: &Path, policy: MimeDetectionPolicy) -> MimeResult<Option<String>> {
self.as_ref().detect_file(file, policy)
}
}
impl MimeDetector for Arc<dyn MimeDetector> {
/// Delegates filename detection to the shared detector.
fn detect_by_filename(&self, filename: &str) -> Option<String> {
self.as_ref().detect_by_filename(filename)
}
/// Delegates content detection to the shared detector.
fn detect_by_content(&self, content: &[u8]) -> Option<String> {
self.as_ref().detect_by_content(content)
}
/// Delegates combined detection to the shared detector.
fn detect(
&self,
content: &[u8],
filename: Option<&str>,
policy: MimeDetectionPolicy,
) -> Option<String> {
self.as_ref().detect(content, filename, policy)
}
/// Delegates reader detection to the shared detector.
fn detect_reader(
&self,
reader: &mut dyn ReadSeek,
filename: Option<&str>,
policy: MimeDetectionPolicy,
) -> MimeResult<Option<String>> {
self.as_ref().detect_reader(reader, filename, policy)
}
/// Delegates file detection to the shared detector.
fn detect_file(&self, file: &Path, policy: MimeDetectionPolicy) -> MimeResult<Option<String>> {
self.as_ref().detect_file(file, policy)
}
}