use core::{borrow::Borrow, cmp::Ordering, ops::Deref};
use crate::{IndexError, OutOfBoundsError, ParseError};
use alloc::string::{String, ToString};
use serde::{Deserialize, Serialize};
const ENCODED_TILDE: &str = "~0";
const ENCODED_SLASH: &str = "~1";
const ENC_PREFIX: char = '~';
const TILDE_ENC: char = '0';
const SLASH_ENC: char = '1';
#[derive(Clone)]
pub struct Token {
value: Value,
}
impl Token {
pub fn new(val: impl AsRef<str>) -> Self {
Token {
value: Value::parse(val.as_ref()),
}
}
pub fn from_encoded(val: impl AsRef<str>) -> Self {
Token {
value: Value::from_encoded(val.as_ref()),
}
}
pub fn decoded(&self) -> &str {
self.value.decoded()
}
pub fn encoded(&self) -> &str {
self.value.encoded()
}
pub fn as_index(&self, len: usize) -> Result<usize, IndexError> {
if self.decoded() == "-" {
Ok(len)
} else {
match self.decoded().parse().map_err(Into::into) {
Ok(idx) => {
if idx > len {
Err(IndexError::OutOfBounds(OutOfBoundsError {
len,
index: idx,
token: self.clone(),
}))
} else {
Ok(idx)
}
}
Err(err) => Err(IndexError::Parse(ParseError {
source: err,
token: self.clone(),
})),
}
}
}
pub fn as_key(&self) -> &String {
self.value.as_key()
}
pub fn as_str(&self) -> &str {
self.value.decoded()
}
}
impl Serialize for Token {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(self.decoded())
}
}
impl<'de> Deserialize<'de> for Token {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Ok(Token::new(s))
}
}
impl Eq for Token {}
impl Deref for Token {
type Target = str;
fn deref(&self) -> &Self::Target {
self.decoded()
}
}
impl From<usize> for Token {
fn from(v: usize) -> Self {
Token::new(v.to_string())
}
}
impl From<&str> for Token {
fn from(s: &str) -> Self {
Token::new(s)
}
}
impl From<&String> for Token {
fn from(value: &String) -> Self {
Token::new(value.as_str())
}
}
impl From<&&str> for Token {
fn from(value: &&str) -> Self {
Token::new(*value)
}
}
impl From<&usize> for Token {
fn from(value: &usize) -> Self {
Token::new(value.to_string())
}
}
impl From<u32> for Token {
fn from(v: u32) -> Self {
Token::new(v.to_string())
}
}
impl From<&u32> for Token {
fn from(v: &u32) -> Self {
Token::new(v.to_string())
}
}
impl From<u64> for Token {
fn from(v: u64) -> Self {
Token::new(v.to_string())
}
}
impl From<&u64> for Token {
fn from(v: &u64) -> Self {
Token::new(v.to_string())
}
}
impl From<String> for Token {
fn from(value: String) -> Self {
Token::new(value)
}
}
impl AsRef<str> for Token {
fn as_ref(&self) -> &str {
self.decoded()
}
}
impl Borrow<str> for Token {
fn borrow(&self) -> &str {
self.decoded()
}
}
impl Borrow<String> for Token {
fn borrow(&self) -> &String {
match &self.value {
Value::Uncoded(u) => u,
Value::Encoded(e) => &e.decoded,
}
}
}
impl From<&Token> for Token {
fn from(t: &Token) -> Self {
t.clone()
}
}
impl PartialEq<str> for Token {
fn eq(&self, other: &str) -> bool {
self.decoded() == other
}
}
impl PartialEq<Token> for Token {
fn eq(&self, other: &Token) -> bool {
self == other.decoded()
}
}
impl PartialEq<Token> for str {
fn eq(&self, other: &Token) -> bool {
self == other.decoded()
}
}
impl PartialEq<String> for Token {
fn eq(&self, other: &String) -> bool {
self == other
}
}
impl PartialEq<&str> for Token {
fn eq(&self, other: &&str) -> bool {
&self.value.decoded() == other
}
}
impl PartialEq<&String> for Token {
fn eq(&self, other: &&String) -> bool {
&self.value.decoded() == other
}
}
impl PartialEq<Token> for &str {
fn eq(&self, other: &Token) -> bool {
self == &other.value.decoded()
}
}
impl PartialEq<&Token> for String {
fn eq(&self, other: &&Token) -> bool {
self == other.value.decoded()
}
}
impl PartialOrd<str> for Token {
fn partial_cmp(&self, other: &str) -> Option<Ordering> {
self.decoded().partial_cmp(other)
}
}
impl PartialOrd<String> for Token {
fn partial_cmp(&self, other: &String) -> Option<Ordering> {
self.decoded().partial_cmp(other)
}
}
impl PartialOrd<Token> for Token {
fn partial_cmp(&self, other: &Token) -> Option<Ordering> {
self.decoded().partial_cmp(other.decoded())
}
}
impl PartialEq<Token> for String {
fn eq(&self, other: &Token) -> bool {
self == other.decoded()
}
}
impl PartialOrd<Token> for String {
fn partial_cmp(&self, other: &Token) -> Option<Ordering> {
self.as_str().partial_cmp(other.decoded())
}
}
impl core::hash::Hash for Token {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.value.decoded().hash(state)
}
}
impl core::fmt::Debug for Token {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.decoded())
}
}
impl core::fmt::Display for Token {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.decoded())
}
}
impl Ord for Token {
fn cmp(&self, other: &Token) -> Ordering {
self.decoded().cmp(other.decoded())
}
}
#[derive(Clone, Debug)]
enum Value {
Uncoded(String),
Encoded(Encoded),
}
impl Value {
fn decoded(&self) -> &str {
match self {
Value::Uncoded(u) => u,
Value::Encoded(e) => &e.decoded,
}
}
fn encoded(&self) -> &str {
match self {
Value::Uncoded(u) => u,
Value::Encoded(e) => &e.encoded,
}
}
fn as_key(&self) -> &String {
match self {
Value::Uncoded(u) => u,
Value::Encoded(e) => &e.decoded,
}
}
fn from_encoded(s: &str) -> Self {
let mut uncoded = String::with_capacity(s.len());
let mut encoded = String::with_capacity(s.len());
let mut is_encoded = false;
let mut chars = s.chars();
while let Some(c) = chars.next() {
encoded.push(c);
if c == ENC_PREFIX {
let next = chars.next();
if next.is_none() {
uncoded.push(c);
break;
}
let next = next.unwrap();
encoded.push(next);
match next {
SLASH_ENC => {
is_encoded = true;
uncoded.push('/');
}
TILDE_ENC => {
is_encoded = true;
uncoded.push('~');
}
_ => {
uncoded.push(next);
}
}
} else {
uncoded.push(c);
}
}
if is_encoded {
Value::Encoded(Encoded {
encoded,
decoded: uncoded,
})
} else {
Value::Uncoded(uncoded)
}
}
fn parse(s: &str) -> Self {
let mut uncoded = String::with_capacity(s.len());
let mut encoded = String::with_capacity(s.len());
let mut was_encoded = false;
for c in s.chars() {
uncoded.push(c);
match Char::from(c) {
Char::Char(c) => encoded.push(c),
Char::Escaped(e) => {
was_encoded = true;
encoded.push_str(e.into());
}
};
}
if was_encoded {
Value::Encoded(Encoded {
encoded,
decoded: uncoded,
})
} else {
Value::Uncoded(uncoded)
}
}
}
#[derive(Clone, Debug)]
struct Encoded {
encoded: String,
decoded: String,
}
enum Char {
Char(char),
Escaped(Escaped),
}
impl From<char> for Char {
fn from(c: char) -> Self {
match c {
'/' => Char::Escaped(Escaped::Slash),
'~' => Char::Escaped(Escaped::Tilde),
_ => Char::Char(c),
}
}
}
enum Escaped {
Tilde,
Slash,
}
#[allow(clippy::from_over_into)]
impl Into<&str> for Escaped {
fn into(self) -> &'static str {
match self {
Escaped::Tilde => ENCODED_TILDE,
Escaped::Slash => ENCODED_SLASH,
}
}
}