// MIT License - Copyright (c) 2026 wallstop
// Full license text: https://github.com/wallstop/unity-helpers/blob/main/LICENSE
namespace WallstopStudios.UnityHelpers.Utils
{
using System;
using System.Runtime.CompilerServices;
using WallstopStudios.UnityHelpers.Core.Helper;
///
/// Immutable snapshot of pool performance statistics.
///
///
/// Use to retrieve the current snapshot.
/// Statistics are always recorded regardless of pool configuration.
///
public readonly struct PoolStatistics : IEquatable
{
///
/// Tolerance for floating-point equality comparisons.
///
private const float FloatEqualityTolerance = 0.001f;
///
/// The current number of items in the pool.
///
public int CurrentSize { get; }
///
/// The maximum number of items the pool has held at any point.
///
public int PeakSize { get; }
///
/// The total number of times items have been rented from the pool.
///
public long RentCount { get; }
///
/// The total number of times items have been returned to the pool.
///
public long ReturnCount { get; }
///
/// The total number of items purged from the pool for any reason.
///
public long PurgeCount { get; }
///
/// The number of items purged due to idle timeout expiration.
///
public long IdleTimeoutPurges { get; }
///
/// The number of items purged due to pool capacity being exceeded.
///
public long CapacityPurges { get; }
///
/// The number of purge operations that completed fully (purged all eligible items).
///
public long FullPurgeOperations { get; }
///
/// The number of purge operations that were partial (hit MaxPurgesPerOperation limit).
/// Partial purges continue on subsequent Rent/Return/Periodic operations.
///
public long PartialPurgeOperations { get; }
///
/// The current rentals-per-minute rate based on the rolling frequency window.
/// Used for intelligent purge decisions - high-frequency pools keep larger buffers.
///
public float RentalsPerMinute { get; }
///
/// The average time between consecutive rentals in seconds.
/// This represents the inter-arrival time between rental operations, not the duration items are held.
/// Returns 0 if fewer than two rentals have occurred.
///
public float AverageInterRentalTimeSeconds { get; }
///
/// The time of the most recent access (rent or return).
///
public float LastAccessTime { get; }
///
/// Whether this pool is considered high-frequency (10+ rentals/minute).
/// High-frequency pools benefit from larger buffers to avoid GC churn.
///
public bool IsHighFrequency { get; }
///
/// Whether this pool is considered low-frequency (at most 1 rental/minute).
/// Low-frequency pools can be purged more aggressively.
///
public bool IsLowFrequency { get; }
///
/// Whether this pool is considered unused (no access in 5+ minutes).
/// Unused pools are candidates for aggressive purging.
///
public bool IsUnused { get; }
private readonly int _hash;
///
/// Creates a new statistics snapshot.
///
/// Current number of items in the pool.
/// Maximum pool size reached.
/// Total rent operations.
/// Total return operations.
/// Total purge operations.
/// Purges due to idle timeout.
/// Purges due to capacity limits.
/// Purge operations that completed fully.
/// Purge operations that were partial (hit max limit).
/// Current rentals-per-minute rate.
/// Average time between consecutive rentals in seconds.
/// Time of most recent access.
/// Whether this is a high-frequency pool.
/// Whether this is a low-frequency pool.
/// Whether this pool is unused.
public PoolStatistics(
int currentSize,
int peakSize,
long rentCount,
long returnCount,
long purgeCount,
long idleTimeoutPurges,
long capacityPurges,
long fullPurgeOperations = 0,
long partialPurgeOperations = 0,
float rentalsPerMinute = 0f,
float averageInterRentalTimeSeconds = 0f,
float lastAccessTime = 0f,
bool isHighFrequency = false,
bool isLowFrequency = false,
bool isUnused = false
)
{
CurrentSize = currentSize;
PeakSize = peakSize;
RentCount = rentCount;
ReturnCount = returnCount;
PurgeCount = purgeCount;
IdleTimeoutPurges = idleTimeoutPurges;
CapacityPurges = capacityPurges;
FullPurgeOperations = fullPurgeOperations;
PartialPurgeOperations = partialPurgeOperations;
RentalsPerMinute = rentalsPerMinute;
AverageInterRentalTimeSeconds = averageInterRentalTimeSeconds;
LastAccessTime = lastAccessTime;
IsHighFrequency = isHighFrequency;
IsLowFrequency = isLowFrequency;
IsUnused = isUnused;
_hash = Objects.HashCode(
currentSize,
peakSize,
rentCount,
returnCount,
purgeCount,
idleTimeoutPurges,
capacityPurges,
fullPurgeOperations,
partialPurgeOperations,
rentalsPerMinute,
averageInterRentalTimeSeconds,
lastAccessTime,
isHighFrequency,
isLowFrequency,
isUnused
);
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(PoolStatistics other)
{
return _hash == other._hash
&& CurrentSize == other.CurrentSize
&& PeakSize == other.PeakSize
&& RentCount == other.RentCount
&& ReturnCount == other.ReturnCount
&& PurgeCount == other.PurgeCount
&& IdleTimeoutPurges == other.IdleTimeoutPurges
&& CapacityPurges == other.CapacityPurges
&& FullPurgeOperations == other.FullPurgeOperations
&& PartialPurgeOperations == other.PartialPurgeOperations
&& Math.Abs(RentalsPerMinute - other.RentalsPerMinute) < FloatEqualityTolerance
&& Math.Abs(AverageInterRentalTimeSeconds - other.AverageInterRentalTimeSeconds)
< FloatEqualityTolerance
&& Math.Abs(LastAccessTime - other.LastAccessTime) < FloatEqualityTolerance
&& IsHighFrequency == other.IsHighFrequency
&& IsLowFrequency == other.IsLowFrequency
&& IsUnused == other.IsUnused;
}
///
public override bool Equals(object obj)
{
return obj is PoolStatistics other && Equals(other);
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode()
{
return _hash;
}
///
/// Equality operator.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(PoolStatistics left, PoolStatistics right)
{
return left.Equals(right);
}
///
/// Inequality operator.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(PoolStatistics left, PoolStatistics right)
{
return !left.Equals(right);
}
///
public override string ToString()
{
return $"PoolStatistics(CurrentSize={CurrentSize}, Peak={PeakSize}, Rents={RentCount}, "
+ $"Returns={ReturnCount}, Purges={PurgeCount}, IdleTimeout={IdleTimeoutPurges}, "
+ $"Capacity={CapacityPurges}, FullPurgeOps={FullPurgeOperations}, PartialPurgeOps={PartialPurgeOperations}, "
+ $"RentalsPerMin={RentalsPerMinute:F2}, AvgInterRentalTime={AverageInterRentalTimeSeconds:F3}s, "
+ $"LastAccess={LastAccessTime:F2}s, High={IsHighFrequency}, Low={IsLowFrequency}, Unused={IsUnused})";
}
}
}