use bitte::bitte;
use std::sync::Arc;
#[bitte]
trait ArcService {
async fn arc_method(self: Arc<Self>) -> String;
async fn arc_ref_method(self: Arc<Self>) -> String;
async fn regular_ref(&self) -> String;
async fn regular_mut(&mut self) -> String;
async fn by_value(self) -> String;
}
#[derive(Clone)]
struct ServiceImpl {
name: String,
}
impl ArcService for ServiceImpl {
fn arc_method(self: Arc<Self>) -> impl Future<Output = String> + Send
where
Self: Sync,
{
async move { format!("Arc: {}", self.name) }
}
fn arc_ref_method(self: Arc<Self>) -> impl Future<Output = String> + Send
where
Self: Sync,
{
async move { format!("Arc: {}", self.name) }
}
fn regular_ref(&self) -> impl Future<Output = String>
where
Self: Sync,
{
let name = self.name.clone();
async move { format!("&self: {}", name) }
}
fn regular_mut(&mut self) -> impl Future<Output = String> + Send {
self.name.push_str(" (modified)");
let name = self.name.clone();
async move { format!("&mut self: {}", name) }
}
fn by_value(self) -> impl Future<Output = String> {
async move { format!("self: {}", self.name) }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_arc_methods() {
let service = Arc::new(ServiceImpl {
name: "test_service".to_string(),
});
let result = service.clone().arc_method().await;
assert_eq!(result, "Arc: test_service");
let result = service.clone().arc_ref_method().await;
assert_eq!(result, "Arc: test_service");
let result = service.regular_ref().await;
assert_eq!(result, "&self: test_service");
}
#[tokio::test]
async fn test_regular_methods() {
let mut service = ServiceImpl {
name: "mutable_service".to_string(),
};
let result = service.regular_mut().await;
assert_eq!(result, "&mut self: mutable_service (modified)");
assert_eq!(service.name, "mutable_service (modified)");
let service2 = ServiceImpl {
name: "consumed".to_string(),
};
let result = service2.by_value().await;
assert_eq!(result, "self: consumed");
}
#[test]
fn test_arc_futures_are_send_and_sync() {
fn assert_send<T: Send>(_: T) {}
fn assert_sync<T: Sync>(_: T) {}
let service = Arc::new(ServiceImpl {
name: "test".to_string(),
});
let future1 = service.clone().arc_method();
assert_send(future1);
let future2 = service.clone().arc_method();
assert_sync(future2);
let future3 = service.clone().arc_ref_method();
assert_send(future3);
let future4 = service.arc_ref_method();
assert_sync(future4);
}
#[test]
fn test_ref_futures_bounds() {
fn assert_send<T: Send>(_: T) {}
let service = ServiceImpl {
name: "test".to_string(),
};
let future = service.regular_ref();
assert_send(future);
}
}
#[bitte]
trait GenericArcService<T: Send + Sync + 'static> {
async fn process(self: Arc<Self>, value: T) -> T;
}
struct GenericServiceImpl;
impl<T: Send + Sync + 'static> GenericArcService<T> for GenericServiceImpl {
fn process(self: Arc<Self>, value: T) -> impl Future<Output = T> + Send
where
Self: Sync,
{
async move {
tokio::time::sleep(tokio::time::Duration::from_millis(1)).await;
value
}
}
}
#[cfg(test)]
mod generic_arc_tests {
use super::*;
#[tokio::test]
async fn test_generic_arc() {
let service = Arc::new(GenericServiceImpl);
let result = service.clone().process(42).await;
assert_eq!(result, 42);
let result = service.process("hello".to_string()).await;
assert_eq!(result, "hello");
}
}