vorner / arc-swap

Support atomic operations on Arc itself
Apache License 2.0
777 stars 31 forks source link

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

Open stepancheg opened 1 year ago

stepancheg commented 1 year ago

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>.

vorner commented 1 year ago

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:

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.

stepancheg commented 1 year ago

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
}