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(TImpl impl) where TImpl : struct, ICollectionImpl { return new EnumerableWrapper(impl); } } internal struct EnumerableWrapper : ICollection where TImpl : struct, ICollectionImpl { private TImpl _impl; public static EnumerableWrapper Create(TImpl impl) { return new EnumerableWrapper(impl); } public EnumerableWrapper(TImpl impl) { _impl = impl; } public IEnumerator GetEnumerator() { var handle = _impl.Handle; var release = false; RuntimeHelpers.PrepareConstrainedRegions(); try { handle.DangerousAddRef(ref release); if (!release) throw new ObjectDisposedException(_impl.GetType().FullName); for (var list = _impl.GetItems(); list != IntPtr.Zero; list = Wrapper.ListNext(list)) { yield return _impl.PtrToItem(Wrapper.ListData(list)); } } finally { if (release) handle.DangerousRelease(); } } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public int Count { get { var impl = _impl; return impl.Handle.UseHandle((_) => (int) alpm.alpm_list_count(impl.GetItems())); } } public bool Contains(TElement item) { var impl = _impl; switch (item) { case string s: return impl.Handle.UseHandle((_) => alpm.alpm_list_find_str(impl.GetItems(), s) != (IntPtr.Zero)); default: var comparer = EqualityComparer.Default; return _impl.Handle.UseHandle((_) => { for (var list = impl.GetItems(); list != IntPtr.Zero; list = Wrapper.ListNext(list)) { if (comparer.Equals(item, impl.PtrToItem(Wrapper.ListData(list)))) return true; } return false; }); } } public void CopyTo(TElement[] array, int arrayIndex) { var impl = _impl; impl.Handle.UseHandle((_) => { for (var list = impl.GetItems(); list != IntPtr.Zero; list = Wrapper.ListNext(list)) { array[arrayIndex++] = impl.PtrToItem(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; } }