Atproto, add bound string
This commit is contained in:
parent
5bc903b2fa
commit
ee99f119f0
4 changed files with 62 additions and 0 deletions
|
|
@ -13,6 +13,7 @@ time = { version = "0.3.41", features = ["parsing", "formatting"] }
|
|||
tracing-subscriber.workspace = true
|
||||
tracing.workspace = true
|
||||
thiserror.workspace = true
|
||||
unicode-segmentation = "1.9.0"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ pub enum ParseError {
|
|||
Serde(#[from] serde_json::error::Error),
|
||||
#[error("Length of parsed object too long, max: {max:?}, got: {got:?}.")]
|
||||
Length { max: usize, got: usize },
|
||||
#[error("Length of parsed object too short, min: {min:?}, got: {got:?}.")]
|
||||
MinLength { min: usize, got: usize },
|
||||
#[error("Currently Did is enforced, cannot use handle, {handle:?}")]
|
||||
ForceDid { handle: String },
|
||||
#[error("Incorrectly formatted")]
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ macro_rules! basic_string_type {
|
|||
}
|
||||
|
||||
mod authority;
|
||||
mod bound_string;
|
||||
mod cid;
|
||||
mod datetime;
|
||||
mod did;
|
||||
|
|
@ -63,6 +64,7 @@ mod record_key;
|
|||
mod strong_ref;
|
||||
mod uri;
|
||||
pub use authority::Authority;
|
||||
pub use bound_string::BoundString;
|
||||
pub use cid::Cid;
|
||||
pub use datetime::Datetime;
|
||||
pub use did::Did;
|
||||
|
|
|
|||
57
atproto/src/types/bound_string.rs
Normal file
57
atproto/src/types/bound_string.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
use unicode_segmentation::UnicodeSegmentation;
|
||||
use crate::error::{Error, ParseError};
|
||||
use std::{
|
||||
fmt::{Display, Formatter, Result as FmtResult},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
pub struct BoundString<
|
||||
const MIN: usize, const MAX: usize>
|
||||
{
|
||||
value: String,
|
||||
}
|
||||
|
||||
impl<const MIN: usize, const MAX: usize> BoundString<MIN, MAX> {
|
||||
fn check_length(s: &str) -> Result<(), Error> {
|
||||
let grapheme_count: usize = s.graphemes(true).take(MAX + 1).count();
|
||||
if grapheme_count > MAX {
|
||||
return Err(Error::Parse {
|
||||
err: ParseError::Length { max: MAX, got: grapheme_count },
|
||||
object: "String".to_string(),
|
||||
});
|
||||
}
|
||||
if grapheme_count < MIN {
|
||||
return Err(Error::Parse {
|
||||
err: ParseError::MinLength { min: MIN, got: grapheme_count },
|
||||
object: "String".to_string(),
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<const MIN: usize, const MAX: usize> Display for BoundString<MIN, MAX> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||
write!(f, "{}", self.value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const MIN: usize, const MAX: usize> FromStr for BoundString<MIN, MAX> {
|
||||
type Err = Error;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Self::check_length(s)?;
|
||||
|
||||
Ok(BoundString { value: s.to_string() })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, const MIN: usize, const MAX: usize> serde::de::Deserialize<'de>
|
||||
for BoundString<MIN, MAX> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::de::Deserializer<'de>,
|
||||
{
|
||||
let value: String = serde::de::Deserialize::deserialize(deserializer)?;
|
||||
value.parse::<BoundString<MIN,MAX>>().map_err(<D::Error as serde::de::Error>::custom)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue