Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix!: Allow people iterating to modify the key #266

Merged
merged 3 commits into from
Nov 23, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/inline_table.rs
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ use std::iter::FromIterator;
use crate::key::Key;
use crate::repr::Decor;
use crate::table::{Iter, IterMut, KeyValuePairs, TableKeyValue, TableLike};
use crate::{InternalString, Item, Table, Value};
use crate::{InternalString, Item, KeyMut, Table, Value};

/// Type representing a TOML inline table,
/// payload of the `Value::InlineTable` variant
@@ -141,7 +141,7 @@ impl InlineTable {
self.items
.iter_mut()
.filter(|(_, kv)| kv.value.is_value())
.map(|(k, kv)| (&k[..], kv.value.as_value_mut().unwrap())),
.map(|(_, kv)| (kv.key.as_mut(), kv.value.as_value_mut().unwrap())),
)
}

@@ -345,7 +345,7 @@ pub type InlineTableIntoIter = Box<dyn Iterator<Item = (InternalString, Value)>>
/// An iterator type over key/value pairs of an inline table.
pub type InlineTableIter<'a> = Box<dyn Iterator<Item = (&'a str, &'a Value)> + 'a>;
/// A mutable iterator type over key/value pairs of an inline table.
pub type InlineTableIterMut<'a> = Box<dyn Iterator<Item = (&'a str, &'a mut Value)> + 'a>;
pub type InlineTableIterMut<'a> = Box<dyn Iterator<Item = (KeyMut<'a>, &'a mut Value)> + 'a>;

impl TableLike for InlineTable {
fn iter(&self) -> Iter<'_> {
@@ -355,7 +355,7 @@ impl TableLike for InlineTable {
Box::new(
self.items
.iter_mut()
.map(|(key, kv)| (&key[..], &mut kv.value)),
.map(|(_, kv)| (kv.key.as_mut(), &mut kv.value)),
)
}
fn get<'s>(&'s self, key: &str) -> Option<&'s Item> {
103 changes: 103 additions & 0 deletions src/key.rs
Original file line number Diff line number Diff line change
@@ -59,6 +59,11 @@ impl Key {
self
}

/// Access a mutable proxy for the `Key`.
pub fn as_mut(&mut self) -> KeyMut<'_> {
KeyMut { key: self }
}

/// Returns the parsed key value.
pub fn get(&self) -> &str {
&self.key
@@ -89,6 +94,7 @@ impl Key {
/// Auto formats the key.
pub fn fmt(&mut self) {
self.repr = Some(to_key_repr(&self.key));
self.decor.clear();
}

fn try_parse(s: &str) -> Result<Key, parser::TomlError> {
@@ -110,6 +116,35 @@ impl Key {
}
}

impl std::ops::Deref for Key {
type Target = str;

fn deref(&self) -> &Self::Target {
self.get()
}
}

impl<'s> PartialEq<str> for Key {
#[inline]
fn eq(&self, other: &str) -> bool {
PartialEq::eq(self.get(), other)
}
}

impl<'s> PartialEq<&'s str> for Key {
#[inline]
fn eq(&self, other: &&str) -> bool {
PartialEq::eq(self.get(), *other)
}
}

impl<'s> PartialEq<String> for Key {
#[inline]
fn eq(&self, other: &String) -> bool {
PartialEq::eq(self.get(), other.as_str())
}
}

impl std::fmt::Display for Key {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
crate::encode::Encode::encode(self, f, ("", ""))
@@ -169,3 +204,71 @@ impl From<Key> for InternalString {
key.key
}
}

/// A mutable reference to a `Key`
#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub struct KeyMut<'k> {
key: &'k mut Key,
}

impl<'k> KeyMut<'k> {
/// Returns the parsed key value.
pub fn get(&self) -> &str {
self.key.get()
}

/// Returns the key raw representation.
pub fn to_repr(&self) -> Cow<Repr> {
self.key.to_repr()
}

/// Returns the surrounding whitespace
pub fn decor_mut(&mut self) -> &mut Decor {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will allow for more "shoot yourself in the foot" cases, e.g. adding "# comment" to the decor

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is true with all of the decor_mut functions we already expose. Created #267 to track this

self.key.decor_mut()
}

/// Returns the surrounding whitespace
pub fn decor(&self) -> &Decor {
self.key.decor()
}

/// Auto formats the key.
pub fn fmt(&mut self) {
self.key.fmt()
}
}

impl<'k> std::ops::Deref for KeyMut<'k> {
type Target = str;

fn deref(&self) -> &Self::Target {
self.get()
}
}

impl<'s> PartialEq<str> for KeyMut<'s> {
#[inline]
fn eq(&self, other: &str) -> bool {
PartialEq::eq(self.get(), other)
}
}

impl<'s> PartialEq<&'s str> for KeyMut<'s> {
#[inline]
fn eq(&self, other: &&str) -> bool {
PartialEq::eq(self.get(), *other)
}
}

impl<'s> PartialEq<String> for KeyMut<'s> {
#[inline]
fn eq(&self, other: &String) -> bool {
PartialEq::eq(self.get(), other.as_str())
}
}

impl<'k> std::fmt::Display for KeyMut<'k> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&self.key, f)
}
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -99,7 +99,7 @@ pub use crate::inline_table::{
};
pub use crate::internal_string::InternalString;
pub use crate::item::{array, table, value, Item};
pub use crate::key::Key;
pub use crate::key::{Key, KeyMut};
pub use crate::parser::TomlError;
pub use crate::repr::{Decor, Formatted, Repr};
pub use crate::table::{
6 changes: 3 additions & 3 deletions src/table.rs
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ use indexmap::map::IndexMap;
use crate::key::Key;
use crate::repr::Decor;
use crate::value::DEFAULT_VALUE_DECOR;
use crate::{InlineTable, InternalString, Item, Value};
use crate::{InlineTable, InternalString, Item, KeyMut, Value};

/// Type representing a TOML non-inline table
#[derive(Clone, Debug, Default)]
@@ -201,7 +201,7 @@ impl Table {
Box::new(
self.items
.iter_mut()
.map(|(key, kv)| (&key[..], &mut kv.value)),
.map(|(_, kv)| (kv.key.as_mut(), &mut kv.value)),
)
}

@@ -401,7 +401,7 @@ pub type IntoIter = Box<dyn Iterator<Item = (InternalString, Item)>>;
/// An iterator type over `Table`'s key/value pairs.
pub type Iter<'a> = Box<dyn Iterator<Item = (&'a str, &'a Item)> + 'a>;
/// A mutable iterator type over `Table`'s key/value pairs.
pub type IterMut<'a> = Box<dyn Iterator<Item = (&'a str, &'a mut Item)> + 'a>;
pub type IterMut<'a> = Box<dyn Iterator<Item = (KeyMut<'a>, &'a mut Item)> + 'a>;

/// This trait represents either a `Table`, or an `InlineTable`.
pub trait TableLike: crate::private::Sealed {