134 lines
4.4 KiB
C#
134 lines
4.4 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 EnumerableWrapper
|
|
{
|
|
internal static EnumerableWrapper<string, THandle> Create<THandle>(THandle handle,
|
|
Func<THandle, IntPtr> getItems) where THandle : SafeHandle
|
|
{
|
|
return new EnumerableWrapper<string, THandle>(handle, getItems, Marshal.PtrToStringUTF8!);
|
|
}
|
|
|
|
internal static EnumerableWrapper<Depend, THandle> CreateForDepend<THandle>(THandle handle,
|
|
Func<THandle, IntPtr> getItems) where THandle : SafeHandle
|
|
{
|
|
return new EnumerableWrapper<Depend, THandle>(handle, getItems, (ptr) => new Depend(ptr));
|
|
}
|
|
|
|
internal static EnumerableWrapper<Backup, THandle> CreateForBackup<THandle>(THandle handle,
|
|
Func<THandle, IntPtr> getItems) where THandle : SafeHandle
|
|
{
|
|
return new EnumerableWrapper<Backup, THandle>(handle, getItems, (ptr) => new Backup(ptr));
|
|
}
|
|
}
|
|
|
|
internal readonly struct EnumerableWrapper<TElement, THandle> : ICollection<TElement> where THandle : SafeHandle
|
|
{
|
|
private readonly THandle _handle;
|
|
private readonly Func<THandle, IntPtr> _getItems;
|
|
private readonly Func<IntPtr, TElement> _getElement;
|
|
|
|
internal EnumerableWrapper(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 = Detail.ListNext(list))
|
|
{
|
|
yield return _getElement(Detail.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 = Detail.ListNext(list))
|
|
{
|
|
if (comparer.Equals(item, getElement(Detail.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 = Detail.ListNext(list))
|
|
{
|
|
array[arrayIndex++] = getElement(Detail.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;
|
|
}
|
|
} |