0

I am trying to split a string into several parts and store everything in the same struct and I would like to do so without cloning anything.

This is roughly what I have:

Struct:

pub struct PkgName<'a> {
    pub fname: String,
    pub name: &'a str,
    pub ver: &'a str,
}

Impl (minus lifetime params):

impl PkgName {
    //the String move is intended, to avoid cloning
    fn parse(fname: String) -> PkgName {
        let end_name: usize = /* .... */;
        let name = &fname[..end_name];
        let ver = &fname[end_name+1..];
        PkgName {fname, name, ver}
    }
}

I already tried with several combinations of lifetime parameters, to no avail.

Example of desired result:

PkgName {
    fname: "archlinux-keyring-20170823-1",
    name: "archlinux-keyring",
    ver: "20170823-1"
}

Again: name and ver must be slices of fname.


Edit:

After reading the duplicate: Why can't I store a value and a reference to that value in the same struct?

I propose an alternative solution that would involve unsafe code: a new type should store the offset between the fields (target - source) plus an additional offset such that it points to the beginning of the desired string; also it should store the size. It basically still behaves like a reference, so it should implement Deref.

As only offsets are saved in this new type, this is move-safe although, of course, only should apply to immutable fields.

jp48
  • 1,186
  • 10
  • 17
  • 2
    I just read the duplicate answer and it doesn't actually explain how it would be done. Of course I don't want mutation, how would this would be done with rental crate or the owning_ref crate? – jp48 Sep 09 '17 at 20:37
  • Please refer to the edit for another proposed solution that would be move-safe. – jp48 Sep 09 '17 at 21:03
  • *it doesn't actually explain how it would be done* — then you **directly reference** two solutions from that answer that allow you to store a reference alongside the owning item. Then you propose to change your question so that it *doesn't store substrings at all*, but instead stores a string and some integers. This moves the benefit of references from compile time to run time, so of course the compiler won't care. – Shepmaster Sep 13 '17 at 12:43
  • You also [don't need unsafe code](https://play.rust-lang.org/?gist=fa9ee9a1061500ca36008c630ab06c4b&version=stable) for the offset solution. – Shepmaster Sep 13 '17 at 13:12
  • Sorry for the tone of my comment. In my defense: I read that `owning_ref` won't work because I require multiple self-references and I still don't know how it would be done with rental (that's what I referred as "it doesn't actually explain that", apologies for the poor choice of words). – jp48 Sep 14 '17 at 13:36
  • Regarding the offset solution, thanks for your input and solution, I actually ended up doing something similar. Anyways, I'm still mildly uncomfortable that the addition is performed in every access instead of updating a raw pointer on creation and move (hence the `unsafe`ness), but I guess that would warrant a separate question. But I see two problems: 1. making sure UTF-8 character boundaries are respected and 2. detecting the "move" (maybe not possible? https://www.reddit.com/49wfej/ ). A perfect solution would also make it transparent by allowing to use nearly the same API as in `&str`. – jp48 Sep 14 '17 at 13:41
  • 1
    No worries, I didn't detect any kind of negative tone! *that the addition is performed in every access instead of updating a raw pointer on creation and move* I guess it depends on how often you move the value vs access it. If you were really worried about it, you could "cache" the result of `&*foo` into a local `&str` variable, relying on normal lifetimes at that point. *making sure UTF-8 character boundaries are respected* — slicing a string will panic if it's not on a character boundary, so that's taken care of for you. – Shepmaster Sep 14 '17 at 14:18
  • 1
    FWIW, [rental had a small bug](https://github.com/jpernst/rental/issues/20#event-1249801514) regarding storing references, but it's fixed now! – Shepmaster Sep 14 '17 at 18:44
  • Wow, thanks for reporting! I thought that was "by design". Will try that right away, even if only for the purpose of learning; for the time being I'm using the working solution in my project which has grown a bit since I implemented it. – jp48 Sep 15 '17 at 21:11

0 Answers0