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 Create(THandle handle, Func getItems) where THandle : SafeHandle { return new EnumerableWrapper(handle, getItems, Marshal.PtrToStringUTF8!); } internal static EnumerableWrapper CreateForDepend(THandle handle, Func getItems) where THandle : SafeHandle { return new EnumerableWrapper(handle, getItems, (ptr) => new Depend(ptr)); } internal static EnumerableWrapper CreateForBackup(THandle handle, Func getItems) where THandle : SafeHandle { return new EnumerableWrapper(handle, getItems, (ptr) => new Backup(ptr)); } } internal readonly struct EnumerableWrapper : ICollection where THandle : SafeHandle { private readonly THandle _handle; private readonly Func _getItems; private readonly Func _getElement; internal EnumerableWrapper(THandle handle, Func getItems, Func getElement) { _handle = handle; _getItems = getItems; _getElement = getElement; } public IEnumerator 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.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; } }