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

Support dotted keys #73

Closed
wants to merge 10 commits into from
Closed

Support dotted keys #73

wants to merge 10 commits into from

Conversation

ironyman
Copy link

When a dotted key a.b.c is created as a child of table T, we create a dotted key marker in T and descend into child tables of T: a, b then create the dotted key a.b.c. The dotted key marker contains the path to the real dotted key. The display walker will print the the dotted key when it finds the dotted key marker by descending into the child tables according to the path in the dotted key marker.

Insert and remove works.

        // Remove works.
        root["a.b"] = value(3);
        assert!(root["a"]["b"].as_integer().unwrap() == 3);
        root.remove("a.b");
        
        // Repeated insert and remove works.
        root["a.c"] = value(2);
        root.remove("a.b");
        root["a.c"] = value("string");
        root.remove("a.b");
        root["a.c"] = value("derp");

Also sorting works.

Copy link
Member

@ordian ordian left a comment

Choose a reason for hiding this comment

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

I had a brief look and the general direction seems right. The thing we need to think about is what we'd like to expose in the public API to make it easy to use and ergonomic.

#[derive(Eq, PartialEq, Clone, Debug, Hash)]
pub(crate) struct Repr {
#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Debug, Hash)]
pub struct Repr {
Copy link
Member

Choose a reason for hiding this comment

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

is it used in pub API?

@@ -8,15 +8,15 @@ pub struct Formatted<T> {

// String representation of a key or a value
// together with a decoration.
#[derive(Eq, PartialEq, Clone, Debug, Hash)]
pub(crate) struct Repr {
#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Debug, Hash)]
Copy link
Member

Choose a reason for hiding this comment

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

I don't think the derived ordering is "correct" here, it will first compare prefix, then suffixes, then raw_value

)))
// From spec:
// simple-key = quoted-key / unquoted-key
// actual: key = unquoted-key / basic-string / literal-string
Copy link
Member

Choose a reason for hiding this comment

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

it was implemented using an older version of spec, so if it has changed, the comment is worth updating as well

Copy link
Author

Choose a reason for hiding this comment

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

You mean the code should be updated? I added the comment to remind us the parser branches differently than the spec but the result is the same.

Copy link
Member

Choose a reason for hiding this comment

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

I've adapted the spec in comments to the parser in some places, so sometimes it's not a direct copy-paste. From your comment change it's not clear whether they are equivalent, so it would be good to update the comment to clarify that.

/// Type for display walker to know where (during walk) to
/// print dotted key. To get value, parse
/// the key and descend table tree.
DottedKeyMarker(Vec<SimpleKey>),
Copy link
Member

Choose a reason for hiding this comment

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

i don't like that the internal implementation detail is leaking into the public API

Copy link
Author

Choose a reason for hiding this comment

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

Should we make Item opaque to the user?

Copy link
Member

Choose a reason for hiding this comment

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

Hmm, I'm not sure. Currently, it's possible to delete an item using table['key'] = Item::None and I'd like to avoid unnecessary breaking changes unless there is a good reason for that. Again, let's think about what kind of API we'd like to expose the user (primarity cargo-edit), and go from that.

@andrewhickman andrewhickman mentioned this pull request Sep 3, 2020
6 tasks
@ghost

This comment has been minimized.

@ironyman
Copy link
Author

I'm not sure what the others' positions are on this. I thought @ordian wanted some time to figure out how we should do the public API for manipulating dotted keys. And some folks in cargo-edit wanted to try another toml library. So I'm not sure where we are.

Copy link
Member

@ordian ordian left a comment

Choose a reason for hiding this comment

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

This PR contains some uncommented code and unresolved TODOs. I'd like it to be resolved before it's merged.

Also not sure if it matches the newest spec
https://toml.io/en/v1.0.0-rc.3#keys

@@ -26,11 +27,36 @@ use std::str::FromStr;
///
/// To parse a key use `FromStr` trait implementation: `"string".parse::<Key>()`.
#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Clone)]
pub struct Key {
pub struct SimpleKey {
Copy link
Member

Choose a reason for hiding this comment

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

How about SingleKey? Also the doccomments need to be updated.

Copy link
Member

Choose a reason for hiding this comment

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

I was thinking of going a different direction and having Key and KeyPath or something.

One thing benefit of "SimpleKey" is that this is the term the grammar uses

raw: InternalString,
pub(crate) parts: Vec<SimpleKey>,
Copy link
Member

Choose a reason for hiding this comment

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

do we need to store raw representation or is it always constructible from the parts?

}

/// Returns the parsed key value.
pub fn get(&self) -> InternalString {
Copy link
Member

Choose a reason for hiding this comment

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

the name InternalString suggests it's not for public API, we can return a String instead, but I'd prefer a IntoString impl or something like that.

let keys_parts: Vec<_> = self.parts.iter().map(|k| k.raw.clone()).collect();
keys_parts.join(".")

// same as raw()?
Copy link
Member

Choose a reason for hiding this comment

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

seems like it

Comment on lines +109 to +122
/// Returns the key raw representation.
pub fn raw(&self) -> &str {
&self.raw
}

/// Get key path.
pub fn get_key_path(&self) -> &[SimpleKey] {
&self.parts
}

/// Get key path.
pub fn get_string_path(&self) -> Vec<InternalString> {
self.parts.iter().map(|r| r.key.clone()).collect()
}
Copy link
Member

Choose a reason for hiding this comment

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

I'm not convinced we need this.

/// Type for display walker to know where (during walk) to
/// print dotted key. To get value, parse
/// the key and descend table tree.
DottedKeyMarker(Vec<SimpleKey>),
Copy link
Member

Choose a reason for hiding this comment

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

This is public API, if we do table['key'] = Item::DottedKeyMarker(vec!['a'.parse().unwrap(), 'b'.parse().unwrap()]);
what would it yield?
This part is the biggest concern with this PR.

Item::DottedKeyMarker(parsed_key.parts.clone())
));
TomlParser::descend_path(self, &path[..path.len() - 1], 0, true)
.expect("the table path is valid; qed")
Copy link
Member

Choose a reason for hiding this comment

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

hmm, looking at this function it always return Ok (or panics).
Looks like something was lost in a refactoring.

root["d.b.d"] = value(1);
root["c.b.d"] = value(1);
root["b.b.d"] = value(1);
root["a.'c'.d"] = value(3);
Copy link
Member

Choose a reason for hiding this comment

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

would be good to also test something like

site."google.com" = true

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants