use std::ffi::{OsStr, OsString};
use std::path::{Path, PathBuf};
use std::sync::{Mutex, OnceLock, RwLock};
use alloc::borrow::Cow;
use alloc::boxed::Box;
use alloc::string::String;
use crate::adapters::Same;
use crate::de::impls::{Via, deserialize_via, via_handle};
use crate::de::{Deserialize, Sink, SinkHandle};
use crate::error::{Error, ErrorKind};
use crate::event::Atom;
use crate::ser::{Chunk, Describe, Serialize};
use crate::{State, Text};
make_slot_wrapper!(SlotWrapper);
impl<T: Serialize + Send> Serialize for OnceLock<T> {
fn serialize(&self, state: &mut State) -> Result<Chunk<'_>, Error> {
match self.get() {
Some(value) => value.serialize(state),
None => Ok(Chunk::Atom(Atom::Null)),
}
}
fn finish(&self, state: &mut State) -> Result<(), Error> {
match self.get() {
Some(value) => value.finish(state),
None => Ok(()),
}
}
fn is_optional(&self) -> bool {
self.get().is_none()
}
fn container_shape(&self) -> crate::ContainerShape {
match self.get() {
Some(value) => value.container_shape(),
None => crate::ContainerShape::new(),
}
}
fn describe(&self, d: &mut dyn Describe) {
match self.get() {
Some(value) => {
d.some();
value.describe(d);
}
None => d.none(),
}
}
}
impl<T: Send> Via<Option<T>> for OnceLock<T> {
#[inline]
fn convert(value: Option<T>) -> Result<Self, Error> {
Ok(match value {
Some(value) => OnceLock::from(value),
None => OnceLock::new(),
})
}
}
impl<'de, T: Deserialize<'de>> Deserialize<'de> for OnceLock<T> {
fn deserialize_into<'out>(
out: &'out mut Option<Self>,
state: &mut State,
) -> SinkHandle<'out, 'de> {
via_handle::<Option<T>, Self, Same>(out, state)
}
fn initial_value() -> Option<Self> {
Some(OnceLock::new())
}
}
impl Serialize for Path {
begin_without_finish!();
fn serialize(&self, _state: &mut State) -> Result<Chunk<'_>, Error> {
match self.to_str() {
Some(value) => Ok(Chunk::Atom(Atom::Str(Text::borrowed(value)))),
None => Err(Error::new(
ErrorKind::Unexpected,
"path contains invalid UTF-8 characters",
)),
}
}
}
impl Serialize for PathBuf {
begin_without_finish!();
fn serialize(&self, state: &mut State) -> Result<Chunk<'_>, Error> {
self.as_path().serialize(state)
}
}
impl<'de> Sink<'de> for SlotWrapper<PathBuf> {
fn expecting(&self) -> Cow<'_, str> {
Cow::Borrowed("path")
}
fn atom(&mut self, atom: Atom, state: &mut State) -> Result<(), Error> {
match atom {
Atom::Str(value) => {
**self = Some(PathBuf::from(value.into_owned()));
Ok(())
}
other => self.unexpected_atom(other, state),
}
}
}
impl<'de> Deserialize<'de> for PathBuf {
fn deserialize_into<'out>(
out: &'out mut Option<Self>,
_state: &mut State,
) -> SinkHandle<'out, 'de> {
SlotWrapper::make_handle(out)
}
#[inline]
fn __private_atom_into(
out: &mut Option<Self>,
atom: Atom,
state: &mut State,
) -> Result<(), Error> {
let sink = SlotWrapper::wrap(out);
sink.atom(atom, state)?;
sink.finish(state)
}
#[inline]
fn __private_borrowed_atom_into(
out: &mut Option<Self>,
atom: Atom<'de>,
state: &mut State,
) -> Result<(), Error> {
Self::__private_atom_into(out, atom, state)
}
}
impl Via<PathBuf> for Box<Path> {
#[inline]
fn convert(value: PathBuf) -> Result<Self, Error> {
Ok(value.into_boxed_path())
}
}
deserialize_via! {
[] Box<Path> => PathBuf;
}
impl Serialize for OsStr {
begin_without_finish!();
fn serialize(&self, _state: &mut State) -> Result<Chunk<'_>, Error> {
match self.to_str() {
Some(value) => Ok(Chunk::Atom(Atom::Str(Text::borrowed(value)))),
None => Err(Error::new(
ErrorKind::Unexpected,
"OS string contains invalid UTF-8 characters",
)),
}
}
}
impl Serialize for OsString {
begin_without_finish!();
fn serialize(&self, state: &mut State) -> Result<Chunk<'_>, Error> {
self.as_os_str().serialize(state)
}
}
impl Via<String> for OsString {
#[inline]
fn convert(value: String) -> Result<Self, Error> {
Ok(OsString::from(value))
}
}
impl Via<OsString> for Box<OsStr> {
#[inline]
fn convert(value: OsString) -> Result<Self, Error> {
Ok(value.into_boxed_os_str())
}
}
deserialize_via! {
[] OsString => String;
[] Box<OsStr> => OsString;
}
impl<T: Send> Via<T> for Mutex<T> {
#[inline]
fn convert(value: T) -> Result<Self, Error> {
Ok(Mutex::new(value))
}
}
impl<T: Send> Via<T> for RwLock<T> {
#[inline]
fn convert(value: T) -> Result<Self, Error> {
Ok(RwLock::new(value))
}
}
deserialize_via! {
[T: Deserialize<'de>] Mutex<T> => T;
[T: Deserialize<'de>] RwLock<T> => T;
}