using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace Foodsoft.Alpm { public struct FileList : IReadOnlyList { private readonly SafePackageHandle _handle; private readonly IntPtr _ptr; internal FileList(SafePackageHandle handle, IntPtr ptr) { _handle = handle; _ptr = ptr; } public File? Contains(string path) { return _handle.UseHandle(_ptr, (ptr) => { var foundPtr = alpm.alpm_filelist_contains(ptr, path); return foundPtr != IntPtr.Zero ? new File(foundPtr) : (File?) null; }); } public IEnumerator GetEnumerator() { var release = false; RuntimeHelpers.PrepareConstrainedRegions(); try { _handle.DangerousAddRef(ref release); if (!release) throw new ObjectDisposedException(_handle.GetType().FullName); var arrayPtr = FileArray(_ptr, out var count); for (var i = 0; i < count; ++i) { yield return new File(FilePtr(arrayPtr, i)); } } finally { if (release) _handle.DangerousRelease(); } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public int Count => _handle.UseHandle(_ptr, FileCount); public File this[int index] { get { return _handle.UseHandle(_ptr, (ptr) => { var arrayPtr = FileArray(ptr, out var count); if (index >= count || index < 0) throw new ArgumentOutOfRangeException(nameof(index), index, $"Exceeds size {count}"); return new File(FilePtr(arrayPtr, index)); }); } } [StructLayout(LayoutKind.Sequential)] private readonly unsafe struct NativeFileList { internal readonly UIntPtr count; internal readonly File.NativeFile* files; } private static unsafe IntPtr FilePtr(IntPtr array, int i) { return (IntPtr) ((File.NativeFile*) array + i); } private static unsafe IntPtr FileArray(IntPtr ptr, out int count) { var list = (NativeFileList*) ptr; count = (int) list->count; return (IntPtr) list->files; } private static unsafe int FileCount(IntPtr ptr) { var list = (NativeFileList*) ptr; return (int) list->count; } } }