#![forbid(unsafe_code, future_incompatible)]
#![deny(
missing_debug_implementations,
nonstandard_style,
missing_copy_implementations,
unused_qualifications
)]
use std::{
convert::{Infallible, TryFrom, TryInto},
fmt::{self, Debug, Display, Formatter, Write},
ops::{Deref, DerefMut, Index},
str::FromStr,
};
mod indexer;
pub use indexer::Indexer;
mod index_path;
pub use index_path::IndexPath;
mod value;
pub use value::Value;
mod error;
pub use error::{Error, ParseErrors, ParseResult, Result};
mod percent_coding;
pub(crate) use percent_coding::{decode, encode};
#[derive(Clone, PartialEq, Eq)]
pub struct QueryStrong<'a> {
value: Value<'a>,
errors: Option<ParseErrors<'a>>,
}
impl<'a> QueryStrong<'a> {
pub fn new() -> Self {
Self {
value: Value::new_map(),
errors: None,
}
}
pub fn parse(s: &'a str) -> Self {
let mut querystrong = QueryStrong::new();
let mut remaining = s;
while !remaining.is_empty() {
let kv;
if let Some(ampersand_index) = memchr::memchr(b'&', remaining.as_bytes()) {
kv = &remaining[..ampersand_index];
remaining = &remaining[ampersand_index + 1..];
} else {
kv = remaining;
remaining = "";
}
if !kv.is_empty() {
let (k, v) = if let Some(equals_index) = memchr::memchr(b'=', kv.as_bytes()) {
(&kv[..equals_index], Some(&kv[equals_index + 1..]))
} else {
(kv, None)
};
if let Err(e) = IndexPath::parse(k).and_then(|k| querystrong.append(k, v)) {
querystrong
.errors
.get_or_insert_with(|| ParseErrors::new(s))
.push(e);
}
}
}
querystrong
}
pub fn parse_strict(s: &'a str) -> ParseResult<'a, Self> {
Self::parse(s).into_result()
}
pub fn errors(&self) -> Option<&ParseErrors<'a>> {
self.errors.as_ref()
}
pub fn into_owned(self) -> QueryStrong<'static> {
QueryStrong {
value: self.value.into_owned(),
errors: self.errors.map(ParseErrors::into_owned),
}
}
pub fn into_result(mut self) -> ParseResult<'a, Self> {
match self.errors.take() {
Some(error) => Err(error),
None => Ok(self),
}
}
pub fn unwrap(self) -> Self {
self.into_result().unwrap()
}
}
impl FromStr for QueryStrong<'static> {
type Err = Infallible;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
Ok(QueryStrong::parse(s).into_owned())
}
}
impl<'a> Default for QueryStrong<'a> {
fn default() -> Self {
Self::new()
}
}
impl<'a> Deref for QueryStrong<'a> {
type Target = Value<'a>;
fn deref(&self) -> &Self::Target {
&self.value
}
}
impl<'a> DerefMut for QueryStrong<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.value
}
}
impl<'a: 'b, 'b> IntoIterator for &'a QueryStrong<'b> {
type Item = (IndexPath<'a>, Option<String>);
type IntoIter = Box<dyn Iterator<Item = Self::Item> + 'a>;
fn into_iter(self) -> Self::IntoIter {
Box::new(self.value.into_iter().filter_map(|(k, v)| match (k, v) {
(Some(k), Some(v)) => {
if k.is_empty() || k.front() == Some(&Indexer::Empty) {
Some((IndexPath::try_from(v).ok()?, None))
} else {
Some((k, Some(v)))
}
}
(Some(k), None) => Some((k, None)),
(None, Some(k)) => Some((Indexer::from(k).into(), None)),
(None, None) => None,
}))
}
}
impl<'a, 'b, K> Index<K> for QueryStrong<'b>
where
K: TryInto<IndexPath<'a>>,
{
type Output = Value<'b>;
fn index(&self, key: K) -> &Self::Output {
self.get(key).unwrap()
}
}
impl Display for QueryStrong<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let mut first = true;
for (key, value) in self {
if first {
first = false;
} else {
f.write_char('&')?;
}
f.write_str(&key.to_string())?;
if let Some(value) = value {
f.write_char('=')?;
f.write_str(&value)?;
}
}
Ok(())
}
}
impl Debug for QueryStrong<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Debug::fmt(&self.value, f)
}
}
impl<'a, V: Into<Value<'a>>> From<V> for QueryStrong<'a> {
fn from(value: V) -> Self {
Self {
value: value.into(),
errors: None,
}
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for QueryStrong<'_> {
fn serialize<S: serde::Serializer>(
&self,
serializer: S,
) -> std::result::Result<S::Ok, S::Error> {
self.value.serialize(serializer)
}
}