Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/core/IronPython/Runtime/Binding/ConversionBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -734,8 +734,9 @@ private DynamicMetaObject ConvertFromMemoryToBufferProtocol(DynamicMetaObject se
return new DynamicMetaObject(
AstUtils.Convert(
Ast.New(
typeof(MemoryBufferProtocolWrapper).GetConstructor(new Type[] { fromType }),
AstUtils.Convert(self.Expression, fromType)
typeof(MemoryBufferProtocolWrapper<byte>).GetConstructor([fromType, typeof(string)]),
AstUtils.Convert(self.Expression, fromType),
AstUtils.Constant(null, typeof(string))
),
typeof(IBufferProtocol)
),
Expand Down
91 changes: 45 additions & 46 deletions src/core/IronPython/Runtime/ConversionWrappers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using System.Runtime.InteropServices;

namespace IronPython.Runtime {

Expand Down Expand Up @@ -376,79 +377,77 @@ IEnumerator IEnumerable.GetEnumerator() {
#endregion
}

public sealed class MemoryBufferWrapper : IPythonBuffer {
private readonly ReadOnlyMemory<byte> _rom;
private readonly Memory<byte>? _memory;
private readonly BufferFlags _flags;
public sealed class MemoryBufferProtocolWrapper<T> : IBufferProtocol where T : unmanaged {
private readonly ReadOnlyMemory<T> _rom;
private readonly Memory<T>? _memory;
private readonly string? _format;

public MemoryBufferWrapper(ReadOnlyMemory<byte> memory, BufferFlags flags) {
public MemoryBufferProtocolWrapper(ReadOnlyMemory<T> memory, string? format = null) {
_rom = memory;
_memory = null;
_flags = flags;
_format = format;
}

public MemoryBufferWrapper(Memory<byte> memory, BufferFlags flags) {
public MemoryBufferProtocolWrapper(Memory<T> memory, string? format = null) {
_rom = memory;
_memory = memory;
_flags = flags;
_format = format;
}

public void Dispose() { }

public object Object => _memory ?? _rom;
public IPythonBuffer? GetBuffer(BufferFlags flags, bool throwOnError) {
if (_memory.HasValue) {
return new MemoryBufferWrapper(this, flags);
}

public bool IsReadOnly => !_memory.HasValue;
if (flags.HasFlag(BufferFlags.Writable)) {
if (throwOnError) {
throw Operations.PythonOps.BufferError("ReadOnlyMemory is not writable.");
}
return null;
}

public ReadOnlySpan<byte> AsReadOnlySpan() => _rom.Span;
return new MemoryBufferWrapper(this, flags);
}

public Span<byte> AsSpan() => _memory.HasValue ? _memory.Value.Span : throw new InvalidOperationException("ReadOnlyMemory is not writable");
private sealed unsafe class MemoryBufferWrapper : IPythonBuffer {
private readonly MemoryBufferProtocolWrapper<T> _wrapper;
private readonly BufferFlags _flags;

public MemoryHandle Pin() => _rom.Pin();
public MemoryBufferWrapper(MemoryBufferProtocolWrapper<T> wrapper, BufferFlags flags) {
_wrapper = wrapper;
_flags = flags;
}

public int Offset => 0;
public void Dispose() { }

public string? Format => _flags.HasFlag(BufferFlags.Format) ? "B" : null;
public object Object => _wrapper._memory ?? _wrapper._rom;

public int ItemCount => _rom.Length;
public bool IsReadOnly => !_wrapper._memory.HasValue;

public int ItemSize => 1;
public ReadOnlySpan<byte> AsReadOnlySpan() => MemoryMarshal.Cast<T, byte>(_wrapper._rom.Span);

public int NumOfDims => 1;
public Span<byte> AsSpan()
=> _wrapper._memory.HasValue
? MemoryMarshal.Cast<T, byte>(_wrapper._memory.Value.Span)
: throw new InvalidOperationException("ReadOnlyMemory is not writable");

public IReadOnlyList<int>? Shape => null;
public MemoryHandle Pin() => _wrapper._rom.Pin();

public IReadOnlyList<int>? Strides => null;
public int Offset => 0;

public IReadOnlyList<int>? SubOffsets => null;
}
public string? Format => _flags.HasFlag(BufferFlags.Format) ? _wrapper._format : null;

public class MemoryBufferProtocolWrapper : IBufferProtocol {
private readonly ReadOnlyMemory<byte> _rom;
private readonly Memory<byte>? _memory;
public int ItemCount => _wrapper._rom.Length;

public MemoryBufferProtocolWrapper(ReadOnlyMemory<byte> memory) {
_rom = memory;
_memory = null;
}
public int ItemSize => sizeof(T);

public MemoryBufferProtocolWrapper(Memory<byte> memory) {
_rom = memory;
_memory = memory;
}
public int NumOfDims => 1;

public IPythonBuffer? GetBuffer(BufferFlags flags, bool throwOnError) {
if (_memory.HasValue) {
return new MemoryBufferWrapper(_memory.Value, flags);
}
public IReadOnlyList<int>? Shape => null;

if (flags.HasFlag(BufferFlags.Writable)) {
if (throwOnError) {
throw Operations.PythonOps.BufferError("ReadOnlyMemory is not writable.");
}
return null;
}
public IReadOnlyList<int>? Strides => null;

return new MemoryBufferWrapper(_rom, flags);
public IReadOnlyList<int>? SubOffsets => null;
}
}
}