PoiScript / orgize

A Rust library for parsing org-mode files.
https://poiscript.github.io/orgize/
MIT License
278 stars 34 forks source link

to_owned for orgize::Org #8

Closed calmofthestorm closed 4 years ago

calmofthestorm commented 4 years ago

I've struggled to find an ownership model that works well for keeping parse trees around longer term, rather than doing one pass of processing. Currently I'm working on something that keeps an in-memory parse tree of a set of Org files, and then updates them whenever they change (per inotify) by reparsing just the modified files.

So conceptually, what I'd like to do is something like:

struct Doc {
  org: orgize::Org,
  text: String,
}

struct ServerState {
  docs: HashMap<PathBuf, Doc>,
}

The problem is that the Org struct needs to refer to the text, and thus runs afoul of the borrow checker. In this use case, I'd be fine double storing the text, e.g., if orgize::Org had an into_owned as the elements do (or if Org provided a non-mutating accessor for its text).

Conceptually, there should be a way to get around this without changing Orgize, since this is essentially the opposite of splitting a reference. I found https://github.com/Kimundi/owning-ref-rs and https://github.com/jpernst/rental which I think would let me do that, though I haven't tried yet. If worst comes to worst, I could probably write something unsafe, since the fundamental access pattern should be safe, but it's frustrating to not be able to do the usual "clone to make your problems go away'" trick.

Do you have any thoughts on how best to approach this? Please do let me know if I'm missing something -- I'm somewhat new to Rust.

PoiScript commented 4 years ago

It's good idea to add a to_owned function for Org struct. But it seems impossible to convert an Arena<Element<'a>> to Arena<Element<'static>> (due to the limitations of indextree). I'm still looking for a workaround of creating a Org<'static>, or maybe create a feature request for indextree.

PoiScript commented 4 years ago

I just publish v0.8 and it introduces two new api: parse_string and parse_string_custom which work exactly like parse and parse_custom but accept String and return an owned Org<'static>.

I do want to reuse the parse function, but Rust will always considers Org<'a> and Org<'static> as different types. So I have to make a separate function.

calmofthestorm commented 4 years ago

Thanks for implementing this, it will simplify things for me a lot. The separate function seems fine to me, since it seems unlikely a user would need the flexibility of Cow for the top level Org object.

For adding new headlines, etc, I can just put the Org in a struct with a Vec<Box<String>> to hold the references to the added objects. In any case, my main use case for efficiency is read only.