Livt packages

Livt.Net

Version 1.4.1

Ethernet, IPv4, TCP, UDP, ARP, TFTP, and Telnet networking components for Livt hardware.

Published files (163)

src/packet/ArrayPacketData.lvt

namespace Livt.Net

/**
 * Array-backed packet storage with a contiguous initialized prefix.
 * Publish freezes bytes; Release permits reuse and clears prefix metadata.
 * Release only after all readers/regions have finished. Storage is not erased.
 * Scheduled calls have no fixed-cycle or combinational-access guarantee.
 */
component ArrayPacketData<CAPACITY: int = 128> : IWritablePacketData<PacketDataGeometry<CAPACITY>>
{
	static assert CAPACITY > 0, "Packet capacity must be positive"

	// Owned bytes; only the contiguous initialized prefix may be published.
	data: byte[CAPACITY]

	// Prefix length and publication state; releasing does not erase storage.
	const LENGTH_BITS: int = Bits.RequiredFor(CAPACITY)
	written: logic[LENGTH_BITS]
	published: bool

	/**
	 * Creates owned storage with an empty, unpublished prefix; bytes need not be erased.
	 */
	new()
	{
		written = 0
		published = false
	}

	/**
	 * Returns the fixed storage capacity in bytes; this does not reserve space.
	 */
	override fn GetCapacity() int
	{
		return CAPACITY
	}

	/**
	 * Returns the contiguous initialized prefix length, including unpublished bytes.
	 */
	override fn GetWrittenLength() int
	{
		return (written as uint) as int
	}

	/**
	 * Reports whether the initialized prefix is published for readers.
	 */
	override fn IsReady() bool
	{
		return published
	}

	/**
	 * Returns the published prefix length in bytes, or zero while unpublished.
	 */
	override fn GetAvailableLength() int
	{
		if (!published) {
			return 0
		}

		return (written as uint) as int
	}

	/**
	 * Append the next byte or overwrite an initialized byte; holes are invalid.
	 */
	override fn TryWrite(index: int, value: byte) PacketDataResult
	{
		if (published) {
			return PacketDataResult.Busy
		}

		if (index < 0 || index >= CAPACITY || index > ((written as uint) as int)) {
			return PacketDataResult.Invalid
		}

		data[index] = value

		if (index == ((written as uint) as int)) {
			written++
		}

		return PacketDataResult.Success
	}

	/**
	 * An empty prefix is valid packet data, though not a valid Ethernet TX.
	 */
	override fn TryPublish() PacketDataResult
	{
		if (published) {
			return PacketDataResult.Busy
		}

		published = true
		return PacketDataResult.Success
	}

	/**
	 * Reads index in 0..written-1 from the published prefix. Returns NotReady
	 * while unpublished and Invalid outside the prefix; failure leaves output zero.
	 * The scheduled read must finish before the owner releases storage.
	 */
	override fn TryRead(index: int, value: out byte) PacketDataResult
	{
		value = 0x00

		if (!published) {
			return PacketDataResult.NotReady
		}

		if (index < 0 || index >= ((written as uint) as int)) {
			return PacketDataResult.Invalid
		}

		value = data[index]
		return PacketDataResult.Success
	}

	/**
	 * Releases a published prefix and resets its initialized length without erasing
	 * storage. Returns Invalid if unpublished. Finish all dependent reads first.
	 */
	override fn TryRelease() PacketDataResult
	{
		if (!published) {
			return PacketDataResult.Invalid
		}

		published = false
		written = 0
		return PacketDataResult.Success
	}

	/**
	 * Abandon unpublished preparation; cannot discard a published source.
	 */
	override fn TryClear() PacketDataResult
	{
		if (published) {
			return PacketDataResult.Busy
		}

		written = 0
		return PacketDataResult.Success
	}
}