Files
h-school/src/HSchool.Protocol/PacketReader.cs
T
Leonid PershinandCursor 8e7ab46e79 Sample outdoor weather from the climate preset so people can freeze and the clock can show it.
Protocol v8 adds tenths of a °C and precipitation to the clock frame; warmth drains from insulation versus place temperature.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-20 03:49:40 +03:00

85 lines
2.5 KiB
C#

using System.Buffers.Binary;
using System.Text;
namespace HSchool.Protocol;
/// <summary>Little-endian cursor over a received frame. Mirror of <see cref="PacketWriter"/>.</summary>
public ref struct PacketReader(ReadOnlySpan<byte> buffer)
{
private readonly ReadOnlySpan<byte> _buffer = buffer;
private int _position = 0;
public readonly int Position => _position;
public readonly int Remaining => _buffer.Length - _position;
public byte ReadByte()
{
EnsureAvailable(sizeof(byte));
var value = _buffer[_position];
_position += sizeof(byte);
return value;
}
public MessageType ReadMessageType() => (MessageType)ReadByte();
public ushort ReadUInt16()
{
EnsureAvailable(sizeof(ushort));
var value = BinaryPrimitives.ReadUInt16LittleEndian(_buffer[_position..]);
_position += sizeof(ushort);
return value;
}
public uint ReadUInt32()
{
EnsureAvailable(sizeof(uint));
var value = BinaryPrimitives.ReadUInt32LittleEndian(_buffer[_position..]);
_position += sizeof(uint);
return value;
}
/// <summary><c>u16</c> byte length, then UTF-8. Empty string is a zero length.</summary>
public string ReadString()
{
var byteCount = ReadUInt16();
EnsureAvailable(byteCount);
var value = Encoding.UTF8.GetString(_buffer.Slice(_position, byteCount));
_position += byteCount;
return value;
}
public short ReadInt16()
{
EnsureAvailable(sizeof(short));
var value = BinaryPrimitives.ReadInt16LittleEndian(_buffer[_position..]);
_position += sizeof(short);
return value;
}
public int ReadInt32()
{
EnsureAvailable(sizeof(int));
var value = BinaryPrimitives.ReadInt32LittleEndian(_buffer[_position..]);
_position += sizeof(int);
return value;
}
public long ReadInt64()
{
EnsureAvailable(sizeof(long));
var value = BinaryPrimitives.ReadInt64LittleEndian(_buffer[_position..]);
_position += sizeof(long);
return value;
}
private readonly void EnsureAvailable(int bytes)
{
if (_position + bytes > _buffer.Length)
{
throw new ProtocolException(
$"Truncated frame: need {bytes} bytes at offset {_position}, only {Remaining} available.");
}
}
}