// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.6; import "./RingBufferLib.sol"; /// @title Library for creating and managing a draw ring buffer. library DrawRingBufferLib { /// @notice Draw buffer struct. struct Buffer { uint32 lastDrawId; uint32 nextIndex; uint32 cardinality; } /// @notice Helper function to know if the draw ring buffer has been initialized. /// @dev since draws start at 1 and are monotonically increased, we know we are uninitialized if nextIndex = 0 and lastDrawId = 0. /// @param _buffer The buffer to check. function isInitialized(Buffer memory _buffer) internal pure returns (bool) { return !(_buffer.nextIndex == 0 && _buffer.lastDrawId == 0); } /// @notice Push a draw to the buffer. /// @param _buffer The buffer to push to. /// @param _drawId The drawID to push. /// @return The new buffer. function push(Buffer memory _buffer, uint32 _drawId) internal pure returns (Buffer memory) { require(!isInitialized(_buffer) || _drawId == _buffer.lastDrawId + 1, "DRB/must-be-contig"); return Buffer({ lastDrawId: _drawId, nextIndex: uint32(RingBufferLib.nextIndex(_buffer.nextIndex, _buffer.cardinality)), cardinality: _buffer.cardinality }); } /// @notice Get draw ring buffer index pointer. /// @param _buffer The buffer to get the `nextIndex` from. /// @param _drawId The draw id to get the index for. /// @return The draw ring buffer index pointer. function getIndex(Buffer memory _buffer, uint32 _drawId) internal pure returns (uint32) { require(isInitialized(_buffer) && _drawId <= _buffer.lastDrawId, "DRB/future-draw"); uint32 indexOffset = _buffer.lastDrawId - _drawId; require(indexOffset < _buffer.cardinality, "DRB/expired-draw"); uint256 mostRecent = RingBufferLib.newestIndex(_buffer.nextIndex, _buffer.cardinality); return uint32(RingBufferLib.offset(uint32(mostRecent), indexOffset, _buffer.cardinality)); } }