//! # Representing, reading, and writing Preserves `Value`s as Rust data
//!
//! ```
//! use preserves::value::{IOValue, text, packed};
//! let v: IOValue = text::iovalue_from_str("<hi>")?;
//! let w: IOValue = packed::iovalue_from_bytes(b"\xb4\xb3\x02hi\x84")?;
//! assert_eq!(v, w);
//! assert_eq!(text::TextWriter::encode_iovalue(&v)?, "<hi>");
//! assert_eq!(packed::PackedWriter::encode_iovalue(&v)?, b"\xb4\xb3\x02hi\x84");
//! # Ok::<(), std::io::Error>(())
//! ```
//!
//! Preserves `Value`s are categorized in the following way. The core representation type,
//! [crate::value::repr::Value], reflects this structure. However, most of the time you will
//! work with [IOValue] or some other implementation of trait [NestedValue], which augments an
//! underlying [Value] with [*annotations*][crate::value::repr::Annotations] (e.g. comments) and fixes a strategy
//! for memory management.
//!
#![doc = include_str!("../../doc/value-grammar.md")]
//!
//! ## Memory management
//!
//! Each implementation of [NestedValue] chooses a different point in the space of possible
//! approaches to memory management for `Value`s.
//!
//! ##### `IOValue`
//!
//! The most commonly-used and versatile implementation, [IOValue], uses [std::sync::Arc] for
//! internal links in compound `Value`s. Unlike many of the other implementations of
//! [NestedValue], [IOValue] doesn't offer flexibility in the Rust data type to be used for
//! Preserves [embedded values](https://preserves.dev/preserves.html#embeddeds): instead,
//! embedded values in an [IOValue] are themselves [IOValue]s.
//!
//! ##### `ArcValue<D>`, `RcValue<D>`, and `PlainValue<D>`
//!
//! For control over the Rust type to use for embedded values, choose [ArcValue], [RcValue], or
//! [PlainValue]. Use [ArcValue] when you wish to transfer values among threads. [RcValue] is
//! more niche; it may be useful for complex terms that do not need to cross thread boundaries.
//! [PlainValue] is even more niche: it does not use a reference-counted pointer type, meaning
//! it does not offer any kind of aliasing or sharing among subterms at all.
//!
//! # Parsing, pretty-printing, encoding and decoding `Value`s
//!
//! Modules [reader] and [writer] supply generic [Reader] and [Writer] traits for parsing and
//! unparsing Preserves data. Implementations of [Reader] and [Writer] connect Preserves data
//! to specific transfer syntaxes:
//!
//!  - module [packed] supplies tools for working with the machine-oriented binary syntax
//!  - module [text] supplies tools for working with human-readable text syntax

pub mod boundary;
pub mod de;
pub mod domain;
pub mod magic;
pub mod merge;
pub mod packed;
pub mod reader;
pub mod repr;
pub mod ser;
pub mod signed_integer;
pub mod suspendable;
pub mod text;
pub mod writer;

pub use de::from_value;
pub use de::Deserializer;
pub use domain::DebugDomainEncode;
pub use domain::DomainDecode;
pub use domain::DomainEncode;
pub use domain::DomainParse;
pub use domain::FromStrDomainParse;
pub use domain::IOValueDomainCodec;
pub use domain::NoEmbeddedDomainCodec;
pub use domain::ViaCodec;
pub use merge::merge;
pub use packed::PackedReader;
pub use packed::PackedWriter;
pub use reader::BinarySource;
pub use reader::BytesBinarySource;
pub use reader::ConfiguredReader;
pub use reader::IOBinarySource;
pub use reader::Reader;
pub use reader::Token;
pub use repr::AnnotatedValue;
pub use repr::ArcValue;
pub use repr::AtomClass;
pub use repr::CompoundClass;
pub use repr::Domain;
pub use repr::Double;
pub use repr::DummyValue;
pub use repr::Embeddable;
pub use repr::Float;
pub use repr::IOValue;
pub use repr::Map;
pub use repr::NestedValue;
pub use repr::PlainValue;
pub use repr::RcValue;
pub use repr::Record;
pub use repr::Set;
pub use repr::UnwrappedIOValue;
pub use repr::Value;
pub use repr::ValueClass;
pub use ser::to_value;
pub use ser::Serializer;
pub use text::TextReader;
pub use text::TextWriter;
pub use writer::Writer;

#[doc(hidden)]
pub fn invert_map<A, B>(m: &Map<A, B>) -> Map<B, A>
where
    A: Clone,
    B: Clone + Ord,
{
    m.iter().map(|(a, b)| (b.clone(), a.clone())).collect()
}
