use std::iter::FromIterator;
use crate::key::Key;
use crate::repr::Decor;
use crate::table::{Iter, IterMut, KeyValuePairs, TableKeyValue, TableLike};
use crate::{InternalString, Item, KeyMut, RawString, Table, Value};
#[derive(Debug, Default, Clone)]
pub struct InlineTable {
preamble: RawString,
pub(crate) implicit: bool,
decor: Decor,
pub(crate) span: Option<std::ops::Range<usize>>,
dotted: bool,
pub(crate) items: KeyValuePairs,
}
impl InlineTable {
pub fn new() -> Self {
Default::default()
}
pub(crate) fn with_pairs(items: KeyValuePairs) -> Self {
Self {
items,
..Default::default()
}
}
pub fn into_table(self) -> Table {
let mut t = Table::with_pairs(self.items);
t.fmt();
t
}
}
impl InlineTable {
pub fn get_values(&self) -> Vec<(Vec<&Key>, &Value)> {
let mut values = Vec::new();
let root = Vec::new();
self.append_values(&root, &mut values);
values
}
pub(crate) fn append_values<'s>(
&'s self,
parent: &[&'s Key],
values: &mut Vec<(Vec<&'s Key>, &'s Value)>,
) {
for value in self.items.values() {
let mut path = parent.to_vec();
path.push(&value.key);
match &value.value {
Item::Value(Value::InlineTable(table)) if table.is_dotted() => {
table.append_values(&path, values);
}
Item::Value(value) => {
values.push((path, value));
}
_ => {}
}
}
}
pub fn fmt(&mut self) {
decorate_inline_table(self);
}
pub fn sort_values(&mut self) {
self.items.sort_keys();
for kv in self.items.values_mut() {
match &mut kv.value {
Item::Value(Value::InlineTable(table)) if table.is_dotted() => {
table.sort_values();
}
_ => {}
}
}
}
pub fn sort_values_by<F>(&mut self, mut compare: F)
where
F: FnMut(&Key, &Value, &Key, &Value) -> std::cmp::Ordering,
{
self.sort_values_by_internal(&mut compare);
}
fn sort_values_by_internal<F>(&mut self, compare: &mut F)
where
F: FnMut(&Key, &Value, &Key, &Value) -> std::cmp::Ordering,
{
let modified_cmp = |_: &InternalString,
val1: &TableKeyValue,
_: &InternalString,
val2: &TableKeyValue|
-> std::cmp::Ordering {
match (val1.value.as_value(), val2.value.as_value()) {
(Some(v1), Some(v2)) => compare(&val1.key, v1, &val2.key, v2),
(Some(_), None) => std::cmp::Ordering::Greater,
(None, Some(_)) => std::cmp::Ordering::Less,
(None, None) => std::cmp::Ordering::Equal,
}
};
self.items.sort_by(modified_cmp);
for kv in self.items.values_mut() {
match &mut kv.value {
Item::Value(Value::InlineTable(table)) if table.is_dotted() => {
table.sort_values_by_internal(compare);
}
_ => {}
}
}
}
pub(crate) fn set_implicit(&mut self, implicit: bool) {
self.implicit = implicit;
}
pub(crate) fn is_implicit(&self) -> bool {
self.implicit
}
pub fn set_dotted(&mut self, yes: bool) {
self.dotted = yes;
}
pub fn is_dotted(&self) -> bool {
self.dotted
}
pub fn decor_mut(&mut self) -> &mut Decor {
&mut self.decor
}
pub fn decor(&self) -> &Decor {
&self.decor
}
pub fn key(&self, key: &str) -> Option<&'_ Key> {
self.items.get(key).map(|kv| &kv.key)
}
pub fn key_mut(&mut self, key: &str) -> Option<KeyMut<'_>> {
self.items.get_mut(key).map(|kv| kv.key.as_mut())
}
#[deprecated(since = "0.21.1", note = "Replaced with `key_mut`")]
pub fn key_decor_mut(&mut self, key: &str) -> Option<&mut Decor> {
#![allow(deprecated)]
self.items.get_mut(key).map(|kv| kv.key.leaf_decor_mut())
}
#[deprecated(since = "0.21.1", note = "Replaced with `key_mut`")]
pub fn key_decor(&self, key: &str) -> Option<&Decor> {
#![allow(deprecated)]
self.items.get(key).map(|kv| kv.key.leaf_decor())
}
pub fn set_preamble(&mut self, preamble: impl Into<RawString>) {
self.preamble = preamble.into();
}
pub fn preamble(&self) -> &RawString {
&self.preamble
}
pub fn span(&self) -> Option<std::ops::Range<usize>> {
self.span.clone()
}
pub(crate) fn despan(&mut self, input: &str) {
self.span = None;
self.decor.despan(input);
self.preamble.despan(input);
for kv in self.items.values_mut() {
kv.key.despan(input);
kv.value.despan(input);
}
}
}
impl InlineTable {
pub fn iter(&self) -> InlineTableIter<'_> {
Box::new(
self.items
.iter()
.filter(|&(_, kv)| kv.value.is_value())
.map(|(k, kv)| (&k[..], kv.value.as_value().unwrap())),
)
}
pub fn iter_mut(&mut self) -> InlineTableIterMut<'_> {
Box::new(
self.items
.iter_mut()
.filter(|(_, kv)| kv.value.is_value())
.map(|(_, kv)| (kv.key.as_mut(), kv.value.as_value_mut().unwrap())),
)
}
pub fn len(&self) -> usize {
self.iter().count()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn clear(&mut self) {
self.items.clear();
}
pub fn entry(&'_ mut self, key: impl Into<InternalString>) -> InlineEntry<'_> {
match self.items.entry(key.into()) {
indexmap::map::Entry::Occupied(mut entry) => {
let scratch = std::mem::take(&mut entry.get_mut().value);
let scratch = Item::Value(
scratch
.into_value()
.unwrap_or_else(|_| Value::InlineTable(Default::default())),
);
entry.get_mut().value = scratch;
InlineEntry::Occupied(InlineOccupiedEntry { entry })
}
indexmap::map::Entry::Vacant(entry) => {
InlineEntry::Vacant(InlineVacantEntry { entry, key: None })
}
}
}
pub fn entry_format<'a>(&'a mut self, key: &Key) -> InlineEntry<'a> {
match self.items.entry(key.get().into()) {
indexmap::map::Entry::Occupied(mut entry) => {
let scratch = std::mem::take(&mut entry.get_mut().value);
let scratch = Item::Value(
scratch
.into_value()
.unwrap_or_else(|_| Value::InlineTable(Default::default())),
);
entry.get_mut().value = scratch;
InlineEntry::Occupied(InlineOccupiedEntry { entry })
}
indexmap::map::Entry::Vacant(entry) => InlineEntry::Vacant(InlineVacantEntry {
entry,
key: Some(key.clone()),
}),
}
}
pub fn get(&self, key: &str) -> Option<&Value> {
self.items.get(key).and_then(|kv| kv.value.as_value())
}
pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
self.items
.get_mut(key)
.and_then(|kv| kv.value.as_value_mut())
}
pub fn get_key_value<'a>(&'a self, key: &str) -> Option<(&'a Key, &'a Item)> {
self.items.get(key).and_then(|kv| {
if !kv.value.is_none() {
Some((&kv.key, &kv.value))
} else {
None
}
})
}
pub fn get_key_value_mut<'a>(&'a mut self, key: &str) -> Option<(KeyMut<'a>, &'a mut Item)> {
self.items.get_mut(key).and_then(|kv| {
if !kv.value.is_none() {
Some((kv.key.as_mut(), &mut kv.value))
} else {
None
}
})
}
pub fn contains_key(&self, key: &str) -> bool {
if let Some(kv) = self.items.get(key) {
kv.value.is_value()
} else {
false
}
}
pub fn get_or_insert<V: Into<Value>>(
&mut self,
key: impl Into<InternalString>,
value: V,
) -> &mut Value {
let key = key.into();
self.items
.entry(key.clone())
.or_insert(TableKeyValue::new(Key::new(key), Item::Value(value.into())))
.value
.as_value_mut()
.expect("non-value type in inline table")
}
pub fn insert(&mut self, key: impl Into<InternalString>, value: Value) -> Option<Value> {
let key = key.into();
let kv = TableKeyValue::new(Key::new(key.clone()), Item::Value(value));
self.items
.insert(key, kv)
.and_then(|kv| kv.value.into_value().ok())
}
pub fn insert_formatted(&mut self, key: &Key, value: Value) -> Option<Value> {
let kv = TableKeyValue::new(key.to_owned(), Item::Value(value));
self.items
.insert(InternalString::from(key.get()), kv)
.filter(|kv| kv.value.is_value())
.map(|kv| kv.value.into_value().unwrap())
}
pub fn remove(&mut self, key: &str) -> Option<Value> {
self.items
.shift_remove(key)
.and_then(|kv| kv.value.into_value().ok())
}
pub fn remove_entry(&mut self, key: &str) -> Option<(Key, Value)> {
self.items.shift_remove(key).and_then(|kv| {
let key = kv.key;
kv.value.into_value().ok().map(|value| (key, value))
})
}
pub fn retain<F>(&mut self, mut keep: F)
where
F: FnMut(&str, &mut Value) -> bool,
{
self.items.retain(|key, item| {
item.value
.as_value_mut()
.map(|value| keep(key, value))
.unwrap_or(false)
});
}
}
#[cfg(feature = "display")]
impl std::fmt::Display for InlineTable {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
crate::encode::encode_table(self, f, None, ("", ""))
}
}
impl<K: Into<Key>, V: Into<Value>> Extend<(K, V)> for InlineTable {
fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
for (key, value) in iter {
let key = key.into();
let value = Item::Value(value.into());
let value = TableKeyValue::new(key, value);
self.items
.insert(InternalString::from(value.key.get()), value);
}
}
}
impl<K: Into<Key>, V: Into<Value>> FromIterator<(K, V)> for InlineTable {
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = (K, V)>,
{
let mut table = InlineTable::new();
table.extend(iter);
table
}
}
impl IntoIterator for InlineTable {
type Item = (InternalString, Value);
type IntoIter = InlineTableIntoIter;
fn into_iter(self) -> Self::IntoIter {
Box::new(
self.items
.into_iter()
.filter(|(_, kv)| kv.value.is_value())
.map(|(k, kv)| (k, kv.value.into_value().unwrap())),
)
}
}
impl<'s> IntoIterator for &'s InlineTable {
type Item = (&'s str, &'s Value);
type IntoIter = InlineTableIter<'s>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
fn decorate_inline_table(table: &mut InlineTable) {
for (mut key, value) in table
.items
.iter_mut()
.filter(|(_, kv)| kv.value.is_value())
.map(|(_, kv)| (kv.key.as_mut(), kv.value.as_value_mut().unwrap()))
{
key.leaf_decor_mut().clear();
key.dotted_decor_mut().clear();
value.decor_mut().clear();
}
}
pub type InlineTableIntoIter = Box<dyn Iterator<Item = (InternalString, Value)>>;
pub type InlineTableIter<'a> = Box<dyn Iterator<Item = (&'a str, &'a Value)> + 'a>;
pub type InlineTableIterMut<'a> = Box<dyn Iterator<Item = (KeyMut<'a>, &'a mut Value)> + 'a>;
impl TableLike for InlineTable {
fn iter(&self) -> Iter<'_> {
Box::new(self.items.iter().map(|(key, kv)| (&key[..], &kv.value)))
}
fn iter_mut(&mut self) -> IterMut<'_> {
Box::new(
self.items
.iter_mut()
.map(|(_, kv)| (kv.key.as_mut(), &mut kv.value)),
)
}
fn clear(&mut self) {
self.clear();
}
fn entry<'a>(&'a mut self, key: &str) -> crate::Entry<'a> {
match self.items.entry(key.into()) {
indexmap::map::Entry::Occupied(entry) => {
crate::Entry::Occupied(crate::OccupiedEntry { entry })
}
indexmap::map::Entry::Vacant(entry) => {
crate::Entry::Vacant(crate::VacantEntry { entry, key: None })
}
}
}
fn entry_format<'a>(&'a mut self, key: &Key) -> crate::Entry<'a> {
match self.items.entry(key.get().into()) {
indexmap::map::Entry::Occupied(entry) => {
crate::Entry::Occupied(crate::OccupiedEntry { entry })
}
indexmap::map::Entry::Vacant(entry) => crate::Entry::Vacant(crate::VacantEntry {
entry,
key: Some(key.to_owned()),
}),
}
}
fn get<'s>(&'s self, key: &str) -> Option<&'s Item> {
self.items.get(key).map(|kv| &kv.value)
}
fn get_mut<'s>(&'s mut self, key: &str) -> Option<&'s mut Item> {
self.items.get_mut(key).map(|kv| &mut kv.value)
}
fn get_key_value<'a>(&'a self, key: &str) -> Option<(&'a Key, &'a Item)> {
self.get_key_value(key)
}
fn get_key_value_mut<'a>(&'a mut self, key: &str) -> Option<(KeyMut<'a>, &'a mut Item)> {
self.get_key_value_mut(key)
}
fn contains_key(&self, key: &str) -> bool {
self.contains_key(key)
}
fn insert(&mut self, key: &str, value: Item) -> Option<Item> {
self.insert(key, value.into_value().unwrap())
.map(Item::Value)
}
fn remove(&mut self, key: &str) -> Option<Item> {
self.remove(key).map(Item::Value)
}
fn get_values(&self) -> Vec<(Vec<&Key>, &Value)> {
self.get_values()
}
fn fmt(&mut self) {
self.fmt();
}
fn sort_values(&mut self) {
self.sort_values();
}
fn set_dotted(&mut self, yes: bool) {
self.set_dotted(yes);
}
fn is_dotted(&self) -> bool {
self.is_dotted()
}
fn key(&self, key: &str) -> Option<&'_ Key> {
self.key(key)
}
fn key_mut(&mut self, key: &str) -> Option<KeyMut<'_>> {
self.key_mut(key)
}
fn key_decor_mut(&mut self, key: &str) -> Option<&mut Decor> {
#![allow(deprecated)]
self.key_decor_mut(key)
}
fn key_decor(&self, key: &str) -> Option<&Decor> {
#![allow(deprecated)]
self.key_decor(key)
}
}
pub(crate) const DEFAULT_INLINE_KEY_DECOR: (&str, &str) = (" ", " ");
pub enum InlineEntry<'a> {
Occupied(InlineOccupiedEntry<'a>),
Vacant(InlineVacantEntry<'a>),
}
impl<'a> InlineEntry<'a> {
pub fn key(&self) -> &str {
match self {
InlineEntry::Occupied(e) => e.key(),
InlineEntry::Vacant(e) => e.key(),
}
}
pub fn or_insert(self, default: Value) -> &'a mut Value {
match self {
InlineEntry::Occupied(entry) => entry.into_mut(),
InlineEntry::Vacant(entry) => entry.insert(default),
}
}
pub fn or_insert_with<F: FnOnce() -> Value>(self, default: F) -> &'a mut Value {
match self {
InlineEntry::Occupied(entry) => entry.into_mut(),
InlineEntry::Vacant(entry) => entry.insert(default()),
}
}
}
pub struct InlineOccupiedEntry<'a> {
entry: indexmap::map::OccupiedEntry<'a, InternalString, TableKeyValue>,
}
impl<'a> InlineOccupiedEntry<'a> {
pub fn key(&self) -> &str {
self.entry.key().as_str()
}
pub fn key_mut(&mut self) -> KeyMut<'_> {
self.entry.get_mut().key.as_mut()
}
pub fn get(&self) -> &Value {
self.entry.get().value.as_value().unwrap()
}
pub fn get_mut(&mut self) -> &mut Value {
self.entry.get_mut().value.as_value_mut().unwrap()
}
pub fn into_mut(self) -> &'a mut Value {
self.entry.into_mut().value.as_value_mut().unwrap()
}
pub fn insert(&mut self, value: Value) -> Value {
let mut value = Item::Value(value);
std::mem::swap(&mut value, &mut self.entry.get_mut().value);
value.into_value().unwrap()
}
pub fn remove(self) -> Value {
self.entry.shift_remove().value.into_value().unwrap()
}
}
pub struct InlineVacantEntry<'a> {
entry: indexmap::map::VacantEntry<'a, InternalString, TableKeyValue>,
key: Option<Key>,
}
impl<'a> InlineVacantEntry<'a> {
pub fn key(&self) -> &str {
self.entry.key().as_str()
}
pub fn insert(self, value: Value) -> &'a mut Value {
let entry = self.entry;
let key = self.key.unwrap_or_else(|| Key::new(entry.key().as_str()));
let value = Item::Value(value);
entry
.insert(TableKeyValue::new(key, value))
.value
.as_value_mut()
.unwrap()
}
}