use serde::Serialize;
use validator::Validate;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
pub enum OcrToolType {
#[serde(rename = "hand_write")]
HandWrite,
}
impl OcrToolType {
pub const fn as_str(self) -> &'static str {
match self {
Self::HandWrite => "hand_write",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
pub enum OcrLanguageType {
#[serde(rename = "AUTO")]
Auto,
#[serde(rename = "CHN_ENG")]
ChnEng,
#[serde(rename = "ENG")]
Eng,
#[serde(rename = "JAP")]
Jap,
#[serde(rename = "KOR")]
Kor,
#[serde(rename = "FRE")]
Fre,
#[serde(rename = "SPA")]
Spa,
#[serde(rename = "POR")]
Por,
#[serde(rename = "GER")]
Ger,
#[serde(rename = "ITA")]
Ita,
#[serde(rename = "RUS")]
Rus,
#[serde(rename = "DAN")]
Dan,
#[serde(rename = "DUT")]
Dut,
#[serde(rename = "MAL")]
Mal,
#[serde(rename = "SWE")]
Swe,
#[serde(rename = "IND")]
Ind,
#[serde(rename = "POL")]
Pol,
#[serde(rename = "ROM")]
Rom,
#[serde(rename = "TUR")]
Tur,
#[serde(rename = "GRE")]
Gre,
#[serde(rename = "HUN")]
Hun,
#[serde(rename = "THA")]
Tha,
#[serde(rename = "VIE")]
Vie,
#[serde(rename = "ARA")]
Ara,
#[serde(rename = "HIN")]
Hin,
}
impl OcrLanguageType {
pub const fn as_str(self) -> &'static str {
match self {
Self::Auto => "AUTO",
Self::ChnEng => "CHN_ENG",
Self::Eng => "ENG",
Self::Jap => "JAP",
Self::Kor => "KOR",
Self::Fre => "FRE",
Self::Spa => "SPA",
Self::Por => "POR",
Self::Ger => "GER",
Self::Ita => "ITA",
Self::Rus => "RUS",
Self::Dan => "DAN",
Self::Dut => "DUT",
Self::Mal => "MAL",
Self::Swe => "SWE",
Self::Ind => "IND",
Self::Pol => "POL",
Self::Rom => "ROM",
Self::Tur => "TUR",
Self::Gre => "GRE",
Self::Hun => "HUN",
Self::Tha => "THA",
Self::Vie => "VIE",
Self::Ara => "ARA",
Self::Hin => "HIN",
}
}
}
#[derive(Clone, Serialize, Validate)]
pub struct OcrBody {
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_type: Option<OcrToolType>,
#[serde(skip_serializing_if = "Option::is_none")]
pub language_type: Option<OcrLanguageType>,
#[serde(skip_serializing_if = "Option::is_none")]
pub probability: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
#[validate(length(min = 6, max = 64))]
pub request_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[validate(length(min = 6, max = 128))]
pub user_id: Option<String>,
}
impl std::fmt::Debug for OcrBody {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter
.debug_struct("OcrBody")
.field("tool_type", &self.tool_type)
.field("language_type", &self.language_type)
.field("probability", &self.probability)
.field(
"request_id",
&self.request_id.as_ref().map(|_| "[REDACTED]"),
)
.field("user_id", &self.user_id.as_ref().map(|_| "[REDACTED]"))
.finish()
}
}
impl Default for OcrBody {
fn default() -> Self {
Self::new()
}
}
impl OcrBody {
pub fn new() -> Self {
Self {
tool_type: None,
language_type: None,
probability: None,
request_id: None,
user_id: None,
}
}
pub fn with_tool_type(mut self, tool_type: OcrToolType) -> Self {
self.tool_type = Some(tool_type);
self
}
pub fn with_language_type(mut self, language_type: OcrLanguageType) -> Self {
self.language_type = Some(language_type);
self
}
pub fn with_probability(mut self, probability: bool) -> Self {
self.probability = Some(probability);
self
}
pub fn with_request_id(mut self, request_id: impl Into<String>) -> Self {
self.request_id = Some(request_id.into());
self
}
pub fn with_user_id(mut self, user_id: impl Into<String>) -> Self {
self.user_id = Some(user_id.into());
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn debug_redacts_request_and_user_identifiers() {
let body = OcrBody::new()
.with_request_id("private-request")
.with_user_id("private-user");
let debug = format!("{body:?}");
assert!(!debug.contains("private-request"));
assert!(!debug.contains("private-user"));
}
}