valuable icon indicating copy to clipboard operation
valuable copied to clipboard

Owned [NamedField] for Fields

Open sunng87 opened this issue 3 years ago • 10 comments

The current signature of Fields::Named hold a borrowed slice of NamedField. As far as I can tell, it's designed for 'static definition of rust structs. This makes it difficult to define dynamic Structable for a map like we talked in #53 .

Perhaps we can make it a Cow for the dynamic scenario.

sunng87 avatar Jul 20 '21 15:07 sunng87

@sunng87 just to clarify here, is it the slice that should be owned, or the NamedFields that should be owned?

hawkw avatar Nov 23 '21 18:11 hawkw

@hawkw I think I need for both. I'm trying to construct a Structable from a JSON object, which may have dynamic fields that are determined at runtime, in order to get O(1) access to the fields via valuable API.

Type like this works best for my scenario:

pub enum Fields<'a> {
    /// Named fields
    Named(&'a [NamedField<'a>]),

    OwnedNamed(Vec<OwnedNamedField>),  // where OwnedNamedField hold an owned String instead of str

    /// Unnamed (positional) fields or unit
    Unnamed,
}

sunng87 avatar Nov 24 '21 08:11 sunng87

Right, I'm looking into a possible change like this. But, I'm not totally sure if I understand why this change is necessary. If you have a Vec of field names, can't you just pass a borrowed slice of that Vec into Fields::Named?

hawkw avatar Nov 24 '21 20:11 hawkw

That sounds reasonable. It has been a while since last time I'm running into this issue. Let me check my feature branch again to refresh my context about this.

sunng87 avatar Nov 27 '21 11:11 sunng87

@sunng87 let me know if that solution works out for you; I'd like to get this issue figured out soon, because if we do add code to make owned named fields possible, we would probably have to make some breaking changes, and it would be nice to figure out what's necessary here before releasing 0.1.

hawkw avatar Nov 30 '21 18:11 hawkw

Sorry for late response. I may still have issue with current NamedField vector. My use-case is to implement Structable for serde_json::Value and its internal Map<String, Value>. Because the map has dynamic fields so I use StructDef::Dynamic here.

impl<'a> Structable for Map<String, Json> {
    fn definition(&'a self) -> StructDef<'a> {
        let field_defs: Vec<NamedField<'a>> = Vec::new();
        // add field names

        let fields = Fields::Named(&field_defs);

        let def = StructDef::Dynamic {
            name: "Json",
            fields,
        };

        def
    }
}

There are two issues from this piece of code:

  1. The lifetime 'a from StructDef<'a> should be same as the Map because the field names in StructDef borrows str from the map. But I got error[E0308]: method not compatible with trait with my code above.
  2. The NamedField vector is created within the function so it's impossible to borrow it outside.

OwnedNamed(Vec<OwnedNamedField>) in my previous comment can fix both 1 and 2 issue.

sunng87 avatar Dec 01 '21 15:12 sunng87

Hmm, I see why you can't borrow the fields here, so you're right that an owned variant might be necessary. Thanks for the example!

hawkw avatar Dec 01 '21 17:12 hawkw

Another suggestion is to make name of StructDef::Dynamic an Option<String> because the json object is typically anonymous in term of a type.

sunng87 avatar Dec 02 '21 15:12 sunng87

At some point, I'd say that the type isn't a structable but a mappable.

I think it would be fair to add some additional trait fns that make it easier to work w/ json objects. Eg. get(&str) -> Option<Value<'_>> or something like that.

carllerche avatar Dec 03 '21 18:12 carllerche

The only concern with Mappable is it doesn't seem to have O(1) access to value with given key name.

sunng87 avatar Dec 04 '21 05:12 sunng87