blob: 5bc1d8cae1f906d2488b05f9e0dbf0ea3c671442 [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//! Choose how to store a lazy initializer: box its future to keep the cell movable, pin the cell
//! locally to store the future inline, or share a pinned cell across tasks.
use std::sync::Arc;
use asyncband::once::LazyCell;
#[tokio::main(flavor = "current_thread")]
async fn main() {
// The library stores exactly the future returned by the initializer. Explicitly boxing that
// future keeps the cell movable, without requiring dynamic dispatch.
let boxed = LazyCell::new(|| Box::pin(async { "boxed".to_owned() }));
assert_eq!(LazyCell::force(&boxed).await, "boxed");
// Returning the async future directly stores it inline. The caller pins the cell before the
// first poll, so the future stays at a stable address without a heap allocation.
let inline = LazyCell::new(async || "inline".to_owned());
let mut inline = std::pin::pin!(inline);
assert_eq!(LazyCell::force_pin(inline.as_ref()).await, "inline");
LazyCell::force_pin_mut(inline.as_mut())
.await
.push_str(" future");
assert_eq!(
LazyCell::get(&inline).expect("value is initialized"),
"inline future"
);
// Arc::pin allocates the cell once and keeps its inline future at a stable address. Cloning the
// pinned Arc lets multiple tasks resume the same future without a separate future allocation.
let shared = Arc::pin(LazyCell::new(async || {
tokio::task::yield_now().await;
"shared".to_owned()
}));
let first = tokio::spawn({
let shared = shared.clone();
async move { LazyCell::force_pin(shared.as_ref()).await.clone() }
});
let second = tokio::spawn({
let shared = shared.clone();
async move { LazyCell::force_pin(shared.as_ref()).await.clone() }
});
assert_eq!(first.await.unwrap(), "shared");
assert_eq!(second.await.unwrap(), "shared");
}