use std::ptr::NonNull;
use std::time::Duration;
use mountpoint_s3_crt_sys::{
aws_exponential_backoff_jitter_mode, aws_exponential_backoff_retry_options, aws_retry_strategy,
aws_retry_strategy_new_standard, aws_retry_strategy_release, aws_standard_retry_options,
};
use crate::common::allocator::Allocator;
use crate::common::error::Error;
use crate::io::event_loop::EventLoopGroup;
use crate::CrtError as _;
#[derive(Debug)]
pub struct RetryStrategy {
pub(crate) inner: NonNull<aws_retry_strategy>,
}
impl RetryStrategy {
pub fn standard(allocator: &Allocator, options: &StandardRetryOptions<'_>) -> Result<Self, Error> {
let options = options.to_inner();
let inner = unsafe { aws_retry_strategy_new_standard(allocator.inner.as_ptr(), &options).ok_or_last_error()? };
Ok(Self { inner })
}
}
impl Drop for RetryStrategy {
fn drop(&mut self) {
unsafe {
aws_retry_strategy_release(self.inner.as_ptr());
}
}
}
#[derive(Debug)]
pub struct StandardRetryOptions<'a> {
pub backoff_retry_options: ExponentialBackoffRetryOptions<'a>,
pub initial_bucket_capacity: usize,
}
impl<'a> StandardRetryOptions<'a> {
pub fn default(event_loop_group: &'a mut EventLoopGroup) -> Self {
let backoff_retry_options = ExponentialBackoffRetryOptions::default(event_loop_group);
Self {
backoff_retry_options,
initial_bucket_capacity: 0,
}
}
fn to_inner(&self) -> aws_standard_retry_options {
aws_standard_retry_options {
backoff_retry_options: self.backoff_retry_options.to_inner(),
initial_bucket_capacity: self.initial_bucket_capacity,
}
}
}
#[derive(Debug)]
pub struct ExponentialBackoffRetryOptions<'a> {
pub event_loop_group: &'a mut EventLoopGroup,
pub max_retries: usize,
pub backoff_scale_factor: Duration,
pub jitter_mode: ExponentialBackoffJitterMode,
}
impl<'a> ExponentialBackoffRetryOptions<'a> {
pub fn default(event_loop_group: &'a mut EventLoopGroup) -> Self {
Self {
event_loop_group,
max_retries: 0,
backoff_scale_factor: Duration::from_millis(0),
jitter_mode: ExponentialBackoffJitterMode::Full,
}
}
fn to_inner(&self) -> aws_exponential_backoff_retry_options {
aws_exponential_backoff_retry_options {
el_group: self.event_loop_group.inner.as_ptr(),
max_retries: self.max_retries,
backoff_scale_factor_ms: self.backoff_scale_factor.as_millis().min(u32::MAX as u128) as u32,
jitter_mode: self.jitter_mode.into(),
..Default::default()
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExponentialBackoffJitterMode {
None,
Full,
Decorrelated,
}
impl From<ExponentialBackoffJitterMode> for aws_exponential_backoff_jitter_mode {
fn from(mode: ExponentialBackoffJitterMode) -> Self {
match mode {
ExponentialBackoffJitterMode::None => {
aws_exponential_backoff_jitter_mode::AWS_EXPONENTIAL_BACKOFF_JITTER_NONE
}
ExponentialBackoffJitterMode::Full => {
aws_exponential_backoff_jitter_mode::AWS_EXPONENTIAL_BACKOFF_JITTER_FULL
}
ExponentialBackoffJitterMode::Decorrelated => {
aws_exponential_backoff_jitter_mode::AWS_EXPONENTIAL_BACKOFF_JITTER_DECORRELATED
}
}
}
}