Files
DotNetAlpm/Alpm/EnumerableWrapperEx.cs
2020-04-29 23:47:06 -04:00

123 lines
3.8 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Foodsoft.Alpm
{
internal static class EnumerableWrapperEx<TElement>
{
internal static EnumerableWrapperEx<TElement, THandle> Create<THandle>(THandle handle,
Func<THandle, IntPtr> getItems,
Func<IntPtr, TElement> getElement) where THandle : SafeHandle
{
return new EnumerableWrapperEx<TElement, THandle>(handle, getItems, getElement);
}
}
internal readonly struct EnumerableWrapperEx<TElement, THandle> : ICollection<TElement> where THandle : SafeHandle
{
private readonly THandle _handle;
private readonly Func<THandle, IntPtr> _getItems;
private readonly Func<IntPtr, TElement> _getElement;
internal EnumerableWrapperEx(THandle handle, Func<THandle, IntPtr> getItems, Func<IntPtr, TElement> getElement)
{
_handle = handle;
_getItems = getItems;
_getElement = getElement;
}
public IEnumerator<TElement> GetEnumerator()
{
var release = false;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
_handle.DangerousAddRef(ref release);
if (!release) throw new ObjectDisposedException(_handle.GetType().FullName);
for (var list = _getItems(_handle); list != IntPtr.Zero; list = Wrapper.ListNext(list))
{
yield return _getElement(Wrapper.ListData(list));
}
}
finally
{
if (release)
_handle.DangerousRelease();
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public int Count
{
get
{
var getItems = _getItems;
var handle = _handle;
return handle.UseHandle((_) => (int) alpm.alpm_list_count(getItems(handle)));
}
}
public bool Contains(TElement item)
{
var getItems = _getItems;
var getElement = _getElement;
var handle = _handle;
switch (item)
{
case string s:
return handle.UseHandle((_) => alpm.alpm_list_find_str(getItems(handle), s) != (IntPtr.Zero));
default:
var comparer = EqualityComparer<TElement>.Default;
return handle.UseHandle((_) =>
{
for (var list = getItems(handle); list != IntPtr.Zero; list = Wrapper.ListNext(list))
{
if (comparer.Equals(item, getElement(Wrapper.ListData(list))))
return true;
}
return false;
});
}
}
public void CopyTo(TElement[] array, int arrayIndex)
{
var getItems = _getItems;
var getElement = _getElement;
var handle = _handle;
handle.UseHandle((_) =>
{
for (var list = getItems(handle); list != IntPtr.Zero; list = Wrapper.ListNext(list))
{
array[arrayIndex++] = getElement(Wrapper.ListData(list));
}
return arrayIndex;
});
}
public void Add(TElement item)
{
throw new NotSupportedException();
}
public void Clear()
{
throw new NotSupportedException();
}
public bool Remove(TElement item)
{
throw new NotSupportedException();
}
public bool IsReadOnly => true;
}
}