use super::*;
use nav::*;
use std::fmt::{self as stdfmt, Debug, Display, Write as _};
mod cntr;
mod formatter;
mod maps;
mod prims;
mod seqs;
mod solver;
mod tuples;
pub use self::formatter::{FmtError, Formatter};
const FIELDS_ASSIGNER: &str = " =";
const FIELDS_SEPARATOR: &str = ", ";
const KEYS_ASSIGNER: &str = ":";
const INDENT: usize = 4;
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct FormattingConfig {
pub id_on_primitives: bool,
pub id_on_tuples: bool,
pub id_on_containers: bool,
pub id_on_seqs: bool,
pub id_on_maps: bool,
pub width_limit: Option<u16>,
}
impl Default for FormattingConfig {
fn default() -> Self {
Self {
id_on_primitives: false,
id_on_tuples: true,
id_on_containers: true,
id_on_seqs: false,
id_on_maps: false,
width_limit: Some(60),
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Repr {
Inline,
Concise,
Verbose,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Fmt {
pub id: bool,
pub line: Repr,
}
impl<'a> Kserd<'a> {
pub fn as_str(&self) -> String {
let config = FormattingConfig::default();
self.as_str_with_config(config)
}
pub fn as_str_with_config(&self, config: FormattingConfig) -> String {
let mut formatter = Formatter::new(self);
formatter.apply_config(config);
formatter.write_string(String::new())
}
}
fn write_indent(buf: &mut String, columns: usize) {
(0..columns).for_each(|_| buf.push(' '));
}
fn maybe_write_prim_ident(buf: &mut String, print: bool, ident: Option<&str>) {
if print {
if let Some(ident) = ident {
buf.push('<');
buf.push_str(ident);
buf.push_str("> ");
}
}
}
fn maybe_write_nonprim_ident(buf: &mut String, print: bool, ident: Option<&str>) {
if print {
if let Some(ident) = ident {
buf.push_str(ident);
buf.push(' ');
}
}
}
fn delim_writer<P, B, S>(buf: String, prefix: P, suffix: S, body: B) -> String
where
P: FnOnce(String) -> String,
B: FnOnce(String) -> String,
S: FnOnce(String) -> String,
{
suffix(body(prefix(buf)))
}
fn write_node(buf: String, node: Node, fmts: &[Fmt], col: usize) -> String {
match node.value() {
NodeValue::Primitive => prims::write(buf, node.kserd(), fmts.get(node.index()).unwrap().id),
NodeValue::Tuple(seq) => tuples::write(buf, node, fmts, col, seq),
NodeValue::Cntr(map) => cntr::write(buf, node, fmts, col, true, map),
NodeValue::Seq(seq) => seqs::write(buf, node, fmts, col, seq, None),
NodeValue::Map(map) => maps::write(buf, node, fmts, col, map, None),
}
}
impl<'a> Display for Kserd<'a> {
fn fmt(&self, f: &mut stdfmt::Formatter<'_>) -> stdfmt::Result {
let s = self.as_str_with_config(FormattingConfig::default());
write!(f, "{}", s)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mod_docs_example() {
let cargotoml = Kserd::with_id(
"my-crate",
Value::new_cntr(vec![
(
"package",
Kserd::with_id(
"Package",
Value::new_cntr(vec![
("name", Kserd::new_str("a-crate")),
("version", Kserd::new_str("0.1.0")),
])
.unwrap(),
)
.unwrap(),
),
(
"dependencies",
Kserd::new(Value::Seq(vec![
Kserd::new_cntr(vec![
("name", Kserd::new_str("serde")),
("version", Kserd::new_str("1")),
])
.unwrap(),
Kserd::new_cntr(vec![
("name", Kserd::new_str("rand")),
("version", Kserd::new_str("0.5")),
])
.unwrap(),
])),
),
])
.unwrap(),
)
.unwrap();
let s = cargotoml.as_str();
assert_eq!(
&s,
r#"my-crate (
dependencies = [
(name = "serde", version = "1")
(name = "rand", version = "0.5")
]
package = Package (name = "a-crate", version = "0.1.0")
)"#
);
let config = FormattingConfig {
width_limit: Some(0),
..Default::default()
};
let s = cargotoml.as_str_with_config(config);
assert_eq!(
&s,
r#":my-crate
[[dependencies]]
name = "serde"
version = "1"
[[dependencies]]
name = "rand"
version = "0.5"
[package:Package]
name = "a-crate"
version = "0.1.0"
"#
);
let mut fmtr = Formatter::new(&cargotoml);
fmtr.apply_config(config);
fmtr.inline(
fmtr.nodes()
.filter(|n| n.kserd().id() == Some("Package"))
.map(|n| n.index())
.next()
.unwrap(),
)
.unwrap();
let s = fmtr.write_string(String::new());
assert_eq!(
&s,
r#":my-crate
[[dependencies]]
name = "serde"
version = "1"
[[dependencies]]
name = "rand"
version = "0.5"
package = Package (name = "a-crate", version = "0.1.0")
"#
);
}
#[test]
fn string_formatting_test() {
let s = |s| Kserd::new_str(s).as_str();
assert_eq!(s(""), r#""""#);
assert_eq!(s("Hello, world!"), r#""Hello, world!""#);
assert_eq!(
s("Hello\nWorld"),
r#""Hello
World""#
);
assert_eq!(s("Hello \"World\""), r#"str'Hello "World"'"#);
assert_eq!(
s("'Hello'\n\"World\""),
r##"str#'Hello'
"World"#"##
);
assert_eq!(s("#Hello# \"World\""), r#"str'#Hello# "World"'"#);
}
}