Editor/Output/ArchExtents.cs

Registry and dispatcher for architecture extent providers. It defines a context record, an interface for providers that measure spatial extents, and a sealed table class that enumerates concrete extent providers and forwards Measure calls by ArchKind.

Reflection
namespace Sunless.Architecture;

public readonly record struct ArchExtentContext(
	ArchPlan Plan,
	ArchKit Kit,
	ArchRoom Room,
	ArchBuilding Building,
	ArchTool Tool = null,
	object Host = null );

public interface IArchExtentProvider
{
	ArchKind Kind { get; }

	ArchExtent Measure( object payload, ArchExtentContext context );
}

public sealed class ArchExtents : ArchTable<ArchExtents, ArchKind, IArchExtentProvider>
{
	protected override IEnumerable<IArchExtentProvider> Standing()
	{
		yield return new ArchStairExtentProvider();
		yield return new ArchApproachExtentProvider();
		yield return new ArchPillarExtentProvider();
		yield return new ArchSpanExtentProvider();
		yield return new ArchRoofLightExtentProvider();
		yield return new ArchPipeExtentProvider();
		yield return new ArchBracketExtentProvider();
		yield return new ArchPorchExtentProvider();
		yield return new ArchWalkwayExtentProvider();
		yield return new ArchRoadExtentProvider();
		yield return new ArchBridgeExtentProvider();
		yield return new ArchTunnelExtentProvider();
	}

	protected override ArchKind KeyOf( IArchExtentProvider provider ) => provider.Kind;

	protected override bool Accepts( IArchExtentProvider provider ) => provider.Kind.Known;

	protected override string Collision( IArchExtentProvider standing, IArchExtentProvider provider )
	{
		return $"{provider.Kind.Ident} extent is claimed by both {standing.GetType().Name} and {provider.GetType().Name}";
	}

	public IArchExtentProvider For( ArchKind kind ) => Held( kind );

	public ArchExtent Measure( ArchKind kind, object payload, ArchExtentContext context )
	{
		return For( kind )?.Measure( payload, context ) ?? new ArchExtent();
	}
}