Make GasMixture enumerable

I noticed that enumerating gases is frequently done in an annoying way with Enum.GetValues. So I made it better. Now GasMixture is IEnumerable<(Gas gas, float moles)> and it just works.
This commit is contained in:
PJB3005
2025-01-18 00:50:22 +01:00
parent efd5d644e8
commit 0e840d816a
2 changed files with 72 additions and 3 deletions

View File

@@ -1,4 +1,5 @@
using System.Diagnostics.CodeAnalysis;
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.CompilerServices;
using Content.Shared.Atmos.EntitySystems;
@@ -13,12 +14,12 @@ namespace Content.Shared.Atmos
/// </summary>
[Serializable]
[DataDefinition]
public sealed partial class GasMixture : IEquatable<GasMixture>, ISerializationHooks
public sealed partial class GasMixture : IEquatable<GasMixture>, ISerializationHooks, IEnumerable<(Gas gas, float moles)>
{
public static GasMixture SpaceGas => new() {Volume = Atmospherics.CellVolume, Temperature = Atmospherics.TCMB, Immutable = true};
// No access, to ensure immutable mixtures are never accidentally mutated.
[Access(typeof(SharedAtmosphereSystem), typeof(SharedAtmosDebugOverlaySystem), Other = AccessPermissions.None)]
[Access(typeof(SharedAtmosphereSystem), typeof(SharedAtmosDebugOverlaySystem), typeof(GasEnumerator), Other = AccessPermissions.None)]
[DataField]
public float[] Moles = new float[Atmospherics.AdjustedNumberOfGases];
@@ -249,6 +250,16 @@ namespace Content.Shared.Atmos
return new GasMixtureStringRepresentation(TotalMoles, Temperature, Pressure, molesPerGas);
}
GasEnumerator GetEnumerator()
{
return new GasEnumerator(this);
}
IEnumerator<(Gas gas, float moles)> IEnumerable<(Gas gas, float moles)>.GetEnumerator()
{
return GetEnumerator();
}
public override bool Equals(object? obj)
{
if (obj is GasMixture mix)
@@ -289,6 +300,11 @@ namespace Content.Shared.Atmos
return hashCode.ToHashCode();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public GasMixture Clone()
{
if (Immutable)
@@ -302,5 +318,28 @@ namespace Content.Shared.Atmos
};
return newMixture;
}
public struct GasEnumerator(GasMixture mixture) : IEnumerator<(Gas gas, float moles)>
{
private int _idx = -1;
public void Dispose()
{
// Nada.
}
public bool MoveNext()
{
return ++_idx < Atmospherics.TotalNumberOfGases;
}
public void Reset()
{
_idx = -1;
}
public (Gas gas, float moles) Current => ((Gas)_idx, mixture.Moles[_idx]);
object? IEnumerator.Current => Current;
}
}
}

View File

@@ -0,0 +1,30 @@
using Content.Shared.Atmos;
using NUnit.Framework;
namespace Content.Tests.Shared.Atmos;
[TestFixture, TestOf(typeof(GasMixture))]
[Parallelizable(ParallelScope.All)]
public sealed class GasMixtureTest
{
[Test]
public void TestEnumerate()
{
var mixture = new GasMixture();
mixture.SetMoles(Gas.Oxygen, 20);
mixture.SetMoles(Gas.Nitrogen, 10);
mixture.SetMoles(Gas.Plasma, 80);
var expectedList = new (Gas, float)[Atmospherics.TotalNumberOfGases];
for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++)
{
expectedList[i].Item1 = (Gas)i;
}
expectedList[(int)Gas.Oxygen].Item2 = 20f;
expectedList[(int)Gas.Nitrogen].Item2 = 10f;
expectedList[(int)Gas.Plasma].Item2 = 80f;
Assert.That(mixture, Is.EquivalentTo(expectedList));
}
}