using System;
using System.Text;
using System.Buffers.Binary;
namespace Wasmtime
{
///
/// Represents a WebAssembly memory.
///
public class Memory
{
///
/// The size, in bytes, of a WebAssembly memory page.
///
public const int PageSize = 65536;
///
/// Creates a new memory with the given minimum and maximum page counts.
///
///
///
public Memory(uint minimum = 1, uint maximum = uint.MaxValue)
{
if (minimum == 0)
{
throw new ArgumentException("The minimum cannot be zero..", nameof(minimum));
}
if (maximum < minimum)
{
throw new ArgumentException("The maximum cannot be less than the minimum.", nameof(maximum));
}
Minimum = minimum;
Maximum = maximum;
}
///
/// The minimum memory size (in WebAssembly page units).
///
public uint Minimum { get; private set; }
///
/// The minimum memory size (in WebAssembly page units).
///
public uint Maximum { get; private set; }
///
/// The span of the memory.
///
///
/// The span may become invalid if the memory grows.
///
/// This may happen if the memory is explicitly requested to grow or
/// grows as a result of WebAssembly execution.
///
/// Therefore, the returned Span should not be stored.
///
public unsafe Span Span
{
get
{
var data = Interop.wasm_memory_data(_handle.DangerousGetHandle());
var size = Convert.ToInt32(Interop.wasm_memory_data_size(_handle.DangerousGetHandle()).ToUInt32());
return new Span(data, size);
}
}
///
/// Reads a UTF-8 string from memory.
///
/// The zero-based address to read from.
/// The length of bytes to read.
/// Returns the string read from memory.
public string ReadString(int address, int length)
{
return Encoding.UTF8.GetString(Span.Slice(address, length));
}
///
/// Writes a UTF-8 string at the given address.
///
/// The zero-based address to write to.
/// The string to write.
/// Returns the number of bytes written.
public int WriteString(int address, string value)
{
return Encoding.UTF8.GetBytes(value, Span.Slice(address));
}
///
/// Reads a byte from memory.
///
/// The zero-based address to read from.
/// Returns the byte read from memory.
public byte ReadByte(int address)
{
return Span[address];
}
///
/// Writes a byte to memory.
///
/// The zero-based address to write to.
/// The byte to write.
public void WriteByte(int address, byte value)
{
Span[address] = value;
}
///
/// Reads a short from memory.
///
/// The zero-based address to read from.
/// Returns the short read from memory.
public short ReadInt16(int address)
{
return BinaryPrimitives.ReadInt16LittleEndian(Span.Slice(address, 2));
}
///
/// Writes a short to memory.
///
/// The zero-based address to write to.
/// The short to write.
public void WriteInt16(int address, short value)
{
BinaryPrimitives.WriteInt16LittleEndian(Span.Slice(address, 2), value);
}
///
/// Reads an int from memory.
///
/// The zero-based address to read from.
/// Returns the int read from memory.
public int ReadInt32(int address)
{
return BinaryPrimitives.ReadInt32LittleEndian(Span.Slice(address, 4));
}
///
/// Writes an int to memory.
///
/// The zero-based address to write to.
/// The int to write.
public void WriteInt32(int address, int value)
{
BinaryPrimitives.WriteInt32LittleEndian(Span.Slice(address, 4), value);
}
///
/// Reads a long from memory.
///
/// The zero-based address to read from.
/// Returns the long read from memory.
public long ReadInt64(int address)
{
return BinaryPrimitives.ReadInt64LittleEndian(Span.Slice(address, 8));
}
///
/// Writes a long to memory.
///
/// The zero-based address to write to.
/// The long to write.
public void WriteInt64(int address, long value)
{
BinaryPrimitives.WriteInt64LittleEndian(Span.Slice(address, 8), value);
}
///
/// Reads an IntPtr from memory.
///
/// The zero-based address to read from.
/// Returns the IntPtr read from memory.
public IntPtr ReadIntPtr(int address)
{
if (IntPtr.Size == 4)
{
return (IntPtr)ReadInt32(address);
}
return (IntPtr)ReadInt64(address);
}
///
/// Writes an IntPtr to memory.
///
/// The zero-based address to write to.
/// The IntPtr to write.
public void WriteIntPtr(int address, IntPtr value)
{
if (IntPtr.Size == 4)
{
WriteInt32(address, value.ToInt32());
}
else
{
WriteInt64(address, value.ToInt64());
}
}
///
/// Reads a long from memory.
///
/// The zero-based address to read from.
/// Returns the long read from memory.
public float ReadSingle(int address)
{
unsafe
{
var i = ReadInt32(address);
return *((float*)&i);
}
}
///
/// Writes a single to memory.
///
/// The zero-based address to write to.
/// The single to write.
public void WriteSingle(int address, float value)
{
unsafe
{
WriteInt32(address, *(int*)&value);
}
}
///
/// Reads a double from memory.
///
/// The zero-based address to read from.
/// Returns the double read from memory.
public double ReadDouble(int address)
{
unsafe
{
var i = ReadInt64(address);
return *((double*)&i);
}
}
///
/// Writes a double to memory.
///
/// The zero-based address to write to.
/// The double to write.
public void WriteDouble(int address, double value)
{
unsafe
{
WriteInt64(address, *(long*)&value);
}
}
internal Interop.MemoryHandle Handle
{
get
{
return _handle;
}
set
{
_handle = value;
}
}
private Interop.MemoryHandle _handle;
}
}