vorner / arc-swap

Support atomic operations on Arc itself

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Provide API to go from Guard<Option<Arc<T>>> to Option<Guard<Arc<T>>>

stepancheg opened this issue · comments

The use case is this: configuration is stored in global variable as:

static CFG: ArcSwap<Option<Arc<String>>> = ...

now I want to write a function which returns a configuration, but initializes if it is not initialized yet:

fn get_cfg() -> Guard<Arc<String>> {
  let cfg = CFG.load();
  if cfg.is_some() {
    return ???
  }

  ... initialize
}

I'm thinking there should be an operation like:

impl<T> Guard<Option<Arc<T>>> {
  pub fn transpose(self) -> Option<Guard<Arc<T>>> { ... }
}

Similarly, ArcSwap<Option<Arc<T>>> could have a shortcut:

impl<T> ArcSwap<Option<Arc<T>>> {
  fn load(&self) -> Option<Guard<Arc<T>>> { ... }
}

I don't know if Guard can do it transparently, alternatively, arc_swap can provide something like SomeGuard<T>.

First, I assume you mean ArcSwapOption<String> (which is internally `ArcSwapAny<Option<Arc>>), what you have up there would have too many Arc-layers involved.

Also, I'm not sure if what you describe would rather be done by something like:

Lazy<ArcSwap<String>> = Lazy::new(|| {
    todo!()
});

Given these options, I'm not sure if such transpose would be that useful. On the other hand, I think it should be possible to implement because AFAIK the internal representation of Guard<Arc<T>> and Guard<Option<Arc<T>>> are the same.

If you still think there's a use case for such method, I'd be open for a pull request, but:

  • It should be more generic than just Guard<Option<Arc<T>>> ‒ all the other things run on R: RefCnt, S: Strategy.
  • Shouldn't be a method but rather an inherent function (one shall need to call Guard::transpose(g), not g.transpose, because Guard is a "smart pointer" and shouldn't shadow methods on whatever it points to).
  • I don't like the load shortcut, for two reasons ‒ load already exists for that type and returns something else and as mentioned, need for such operation is likely rare, so I wouldn't like to pollute the "base type" (there's already a lot of methods on it).

If you need some specific pointers on how to get oriented in the code, you can ask, but I don't really have that much spare time lately and won't be able to write the code myself.

would rather be done by something like
Lazy

That was too simplified example, sorry. Proper example should be returning Result.

static CFG: ArcSwap<Option<Arc<MyCfg>>> = ...

fn get_cfg() -> anyhow::Result<Guard<Arc<MyCfg>>> {
  let cfg = CFG.load();
  if cfg.is_some() {
    return ???
  }

  ... initialize, return error if failed to initialize configuration
}