// ReSharper disable MemberCanBePrivate.Global using System.Collections; namespace AIStudio.Tools.AssistantSessions; /// /// Stores one typed value in an assistant session snapshot. /// /// The captured value type. public sealed record AssistantSessionSnapshotField : IAssistantSessionSnapshotField { /// /// Initializes a new typed snapshot field. /// /// The captured value. public AssistantSessionSnapshotField(T value) { this.Value = value; } /// /// Gets the captured value. /// public T Value { get; } /// public Type ValueType => typeof(T); /// public bool TryRead(out TValue? value) { if (this.Value is TValue typedValue) { value = typedValue; return true; } if (this.Value is null && default(TValue) is null) { value = default; return true; } value = default; return false; } /// public bool HasSameValueAs(IAssistantSessionSnapshotField other) => other is AssistantSessionSnapshotField otherField && AreSame(this.Value, otherField.Value); private static bool AreSame(object? value, object? otherValue) { if (ReferenceEquals(value, otherValue)) return true; if (value is null || otherValue is null) return false; // Nobody can change a string or a copied value type behind our back: if (value is string || value.GetType().IsValueType) return value.Equals(otherValue); // // The writer copies lists, sets, and dictionaries for every snapshot, so these never share a // reference. Their items, though, are those of the assistant. Any other object may change // without a new reference, e.g., a record holding a list, so only its reference tells: // if (value is IDictionary dictionary && otherValue is IDictionary otherDictionary) return dictionary.Count == otherDictionary.Count && dictionary.Keys.Cast().All(key => otherDictionary.Contains(key) && AreSame(dictionary[key], otherDictionary[key])); if (value is IEnumerable items && otherValue is IEnumerable otherItems) { var itemList = items.Cast().ToList(); var otherItemList = otherItems.Cast().ToList(); return itemList.Count == otherItemList.Count && itemList.Zip(otherItemList).All(pair => AreSame(pair.First, pair.Second)); } return false; } }