namespace AIStudio.Models.Matching;
///
/// Walks the parts of a normalized model name without cutting it into strings.
///
///
/// The index looks up every part of a name to find the rules which could possibly apply to it. That
/// happens for every model of every configured provider, so the walk itself must not allocate: the
/// parts stay slices of the name they came from. This is both the enumerable and the enumerator,
/// which is what lets foreach use it without an interface in between.
///
/// The normalized model name to walk.
public ref struct ModelIdSegments(ReadOnlySpan normalizedId)
{
private ReadOnlySpan remaining = normalizedId;
///
/// The part the walk currently stands on.
///
public ReadOnlySpan Current { get; private set; } = default;
///
/// Hands foreach the walk itself.
///
/// This walk, at its beginning.
public readonly ModelIdSegments GetEnumerator() => this;
///
/// Steps to the next part of the name.
///
/// True, as long as there was one.
public bool MoveNext()
{
while (!this.remaining.IsEmpty)
{
var separator = this.remaining.IndexOf(ModelId.SEGMENT_SEPARATOR);
if (separator is -1)
{
this.Current = this.remaining;
this.remaining = default;
return true;
}
this.Current = this.remaining[..separator];
this.remaining = this.remaining[(separator + 1)..];
//
// Normalizing leaves no empty part behind, so this only guards against a name which
// never went through it. Skipping is the right answer: an empty part matches nothing.
//
if (!this.Current.IsEmpty)
return true;
}
return false;
}
}