using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; // FIXME: This is increasing the ref-count on AlpmHandle all the time, so this is NOT correct for database handles, // or other handles that have a dispose that is not a no-op. namespace Foodsoft.Alpm { internal class CollectionWrapper : ICollection where TImpl : struct, IItemsAccessor { private TImpl _impl; public CollectionWrapper(TImpl impl) { _impl = impl; } private static unsafe IntPtr ListNext(IntPtr list) => ((alpm_list_t*) list)->next; private static unsafe IntPtr ListData(IntPtr list) => ((alpm_list_t*) list)->data; public IEnumerator GetEnumerator() { var safeAlpmHandle = _impl.SafeAlpmHandle; var release = false; RuntimeHelpers.PrepareConstrainedRegions(); try { safeAlpmHandle.DangerousAddRef(ref release); if (!release) throw new ObjectDisposedException(_impl.GetType().FullName); for (var list = _impl.GetItems(); list != IntPtr.Zero; list = ListNext(list)) { yield return _impl.PtrToItem(ListData(list)); } } finally { if (release) safeAlpmHandle.DangerousRelease(); } } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public void Add(TElement item) { _impl.AddItem(item); } public void Clear() { _impl.SetItems(IntPtr.Zero); } public bool Contains(TElement item) { var safeAlpmHandle = _impl.SafeAlpmHandle; var release = false; RuntimeHelpers.PrepareConstrainedRegions(); try { safeAlpmHandle.DangerousAddRef(ref release); return _impl.FindItem(item) != IntPtr.Zero; } finally { if (release) safeAlpmHandle.DangerousRelease(); } } public void CopyTo(TElement[] array, int arrayIndex) { var safeAlpmHandle = _impl.SafeAlpmHandle; var release = false; RuntimeHelpers.PrepareConstrainedRegions(); try { safeAlpmHandle.DangerousAddRef(ref release); var intPtr = _impl.GetItems(); unsafe { for (var list = (alpm_list_t*) intPtr; list != null; list = alpm.alpm_list_next(list)) { array[arrayIndex++] = _impl.PtrToItem(list->data); } } } finally { if (release) safeAlpmHandle.DangerousRelease(); } } public bool Remove(TElement item) { var err = _impl.RemoveItem(item); if (err < 0) { throw new Exception(alpm.alpm_errno(_impl.SafeAlpmHandle)); } return err == 0; } public int Count { get { var safeAlpmHandle = _impl.SafeAlpmHandle; var release = false; RuntimeHelpers.PrepareConstrainedRegions(); try { safeAlpmHandle.DangerousAddRef(ref release); return (int) alpm.alpm_list_count(_impl.GetItems()); } finally { if (release) safeAlpmHandle.DangerousRelease(); } } } public bool IsReadOnly => false; } }