Hello,
I have a type Span
, which represents a region in a file, and is supposed to hold some data about that region: its location, the file where it belongs, the actual content of that region, maybe even the content of the neighbor lines, ... Since I want to build a lot of these spans, since a lot of them will most likely have overlapping data, and since they never need to modify the data they hold, just to read from it, it makes sense to share the content of a file among all the Span
s that are created while reading it. The problem is that there is no clear owner of that data: the function that reads the file and produces all the Span
s can only own that data for so long; no Span
should own data, since it isn't be clear which one should own it; there is no global state where I can just put all the data in and pass it around.
For this particular situation, it seemed to me that the most appropriate choice was an Rc
, since that's exactly what it provides: readonly shareable data with no clear owner. So for instance I have some fields with Rc<str>
or Rc<Path>
.
Of course, when I create errors, I happily include the span of the concerned objects (that's why I keep them around, to produce nice error messages) in the error, and so far there is no problem.
The problem arises when I write some driver code for my library, and I try to use anyhow
. anyhow
's Error
requires Send + Sync
, which rules out my error type, and so makes anyhow
unusable.
I could turn my Rc
into Arc
, but that strikes me as very wasteful: most of the Span
s I will create will not be included in an error, and yet each of them have to pay the overhead of Arc
.
I could also "take ownership" in the error, that is, in the error, instead of having a Span
, I could have something like an OwnedSpan
which would just turn all the Rc<str>
into String
and all the Rc<Path>
into PathBuf
, because one might argue that errors should be self-sufficient. And yet, I'm not convinced by this solution, among other things because that would require almost duplicating the code for Span
. Then I thought that maybe I need a trait Spannable
or something like that to avoid code duplication, but it looks like I'm missing the easy solution and that I'm trying to build something overly complicated.
On final other solution that was proposed to me was to use a Cow<str>
, but I don't think it fits this problem. At least, in my mental model of how Cow
works, it wouldn't be able to share pieces of a string.
So the question is: what is the proper way to deal with anyhow
? Can I, in some way, make it relax its Send + Sync
condition, that is completely useless for me (I have no threading, no asynchronous code, nothing alike). Is there another smart pointer that could solve this problem?