diff --git a/DBC.cs b/DBC.cs new file mode 100644 index 0000000..7105eb4 --- /dev/null +++ b/DBC.cs @@ -0,0 +1,443 @@ +using System; +using System.Diagnostics; + +namespace DBC.ECS +{ + /// + /// Design By Contract Checks. + /// + /// Each method generates an exception or + /// a trace assertion statement if the contract is broken. + /// + /// + /// This example shows how to call the Require method. + /// Assume DBC_CHECK_PRECONDITION is defined. + /// + /// public void Test(int x) + /// { + /// try + /// { + /// Check.Require(x > 1, "x must be > 1"); + /// } + /// catch (System.Exception ex) + /// { + /// Console.WriteLine(ex.ToString()); + /// } + /// } + /// + /// If you wish to use trace assertion statements, intended for Debug scenarios, + /// rather than exception handling then set + /// + /// Check.UseAssertions = true + /// + /// You can specify this in your application entry point and maybe make it + /// dependent on conditional compilation flags or configuration file settings, e.g., + /// + /// #if DBC_USE_ASSERTIONS + /// Check.UseAssertions = true; + /// #endif + /// + /// You can direct output to a Trace listener. For example, you could insert + /// + /// Trace.Listeners.Clear(); + /// Trace.Listeners.Add(new TextWriterTraceListener(Console.Out)); + /// + /// + /// or direct output to a file or the Event Log. + /// + /// (Note: For ASP.NET clients use the Listeners collection + /// of the Debug, not the Trace, object and, for a Release build, only exception-handling + /// is possible.) + /// + /// + static class Check + { + #region Interface + + /// + /// Precondition check. + /// +#if PROFILER || !DEBUG + [Conditional("__NEVER_DEFINED__")] +#endif + public static void Require(bool assertion, string message) + { + if (UseExceptions) + { + if (!assertion) + throw new PreconditionException(message); + } + else + { + Trace.Assert(assertion, "Precondition: " + message); + } + } + + /// + /// Precondition check. + /// + /// +#if PROFILER || !DEBUG + [Conditional("__NEVER_DEFINED__")] +#endif + public static void Require(bool assertion, string message, Exception inner) + { + if (UseExceptions) + { + if (!assertion) + throw new PreconditionException(message, inner); + } + else + { + Trace.Assert(assertion, "Precondition: " + message); + } + } + + /// + /// Precondition check. + /// + /// +#if PROFILER || !DEBUG + [Conditional("__NEVER_DEFINED__")] +#endif + public static void Require(bool assertion) + { + if (UseExceptions) + { + if (!assertion) + throw new PreconditionException("Precondition failed."); + } + else + { + Trace.Assert(assertion, "Precondition failed."); + } + } + + /// + /// Postcondition check. + /// + /// +#if PROFILER || !DEBUG + [Conditional("__NEVER_DEFINED__")] +#endif + public static void Ensure(bool assertion, string message) + { + if (UseExceptions) + { + if (!assertion) + throw new PostconditionException(message); + } + else + { + Trace.Assert(assertion, "Postcondition: " + message); + } + } + + /// + /// Postcondition check. + /// + /// +#if PROFILER || !DEBUG + [Conditional("__NEVER_DEFINED__")] +#endif + public static void Ensure(bool assertion, string message, Exception inner) + { + if (UseExceptions) + { + if (!assertion) + throw new PostconditionException(message, inner); + } + else + { + Trace.Assert(assertion, "Postcondition: " + message); + } + } + + /// + /// Postcondition check. + /// + /// +#if PROFILER || !DEBUG + [Conditional("__NEVER_DEFINED__")] +#endif + public static void Ensure(bool assertion) + { + if (UseExceptions) + { + if (!assertion) + throw new PostconditionException("Postcondition failed."); + } + else + { + Trace.Assert(assertion, "Postcondition failed."); + } + } + + /// + /// Invariant check. + /// + /// +#if PROFILER || !DEBUG + [Conditional("__NEVER_DEFINED__")] +#endif + public static void Invariant(bool assertion, string message) + { + if (UseExceptions) + { + if (!assertion) + throw new InvariantException(message); + } + else + { + Trace.Assert(assertion, "Invariant: " + message); + } + } + + /// + /// Invariant check. + /// + /// +#if PROFILER || !DEBUG + [Conditional("__NEVER_DEFINED__")] +#endif + public static void Invariant(bool assertion, string message, Exception inner) + { + if (UseExceptions) + { + if (!assertion) + throw new InvariantException(message, inner); + } + else + { + Trace.Assert(assertion, "Invariant: " + message); + } + } + + /// + /// Invariant check. + /// + /// +#if PROFILER || !DEBUG + [Conditional("__NEVER_DEFINED__")] +#endif + public static void Invariant(bool assertion) + { + if (UseExceptions) + { + if (!assertion) + throw new InvariantException("Invariant failed."); + } + else + { + Trace.Assert(assertion, "Invariant failed."); + } + } + + /// + /// Assertion check. + /// +#if PROFILER || !DEBUG + [Conditional("__NEVER_DEFINED__")] +#endif + public static void Assert(bool assertion, string message) + { + if (UseExceptions) + { + if (!assertion) + throw new AssertionException(message); + } + else + { + Trace.Assert(assertion, "Assertion: " + message); + } + } + + /// + /// Assertion check. + /// + /// +#if PROFILER || !DEBUG + [Conditional("__NEVER_DEFINED__")] +#endif + public static void Assert(bool assertion, string message, Exception inner) + { + if (UseExceptions) + { + if (!assertion) + throw new AssertionException(message, inner); + } + else + { + Trace.Assert(assertion, "Assertion: " + message); + } + } + + /// + /// Assertion check. + /// + /// +#if PROFILER || !DEBUG + [Conditional("__NEVER_DEFINED__")] +#endif + public static void Assert(bool assertion) + { + if (UseExceptions) + { + if (!assertion) + throw new AssertionException("Assertion failed."); + } + else + { + Trace.Assert(assertion, "Assertion failed."); + } + } + + /// + /// Set this if you wish to use Trace Assert statements + /// instead of exception handling. + /// (The Check class uses exception handling by default.) + /// + public static bool UseAssertions + { + + get + { + return useAssertions; + } + set + { + useAssertions = value; + } + } + + #endregion // Interface + + #region Implementation + + // No creation + + /// + /// Is exception handling being used? + /// + private static bool UseExceptions + { + get + { + return !useAssertions; + } + } + + // Are trace assertion statements being used? + // Default is to use exception handling. + private static bool useAssertions = false; + + #endregion // Implementation + + } // End Check + + class Trace + { + internal static void Assert(bool assertion, string v) + { +#if NETFX_CORE + System.Diagnostics.Contracts.Contract.Assert(assertion, v); +#else + System.Diagnostics.Trace.Assert(assertion, v); +#endif + } + } + + #region Exceptions + + /// + /// Exception raised when a contract is broken. + /// Catch this exception type if you wish to differentiate between + /// any DesignByContract exception and other runtime exceptions. + /// + /// + public class DesignByContractException : Exception + { + protected DesignByContractException() {} + protected DesignByContractException(string message) : base(message) {} + protected DesignByContractException(string message, Exception inner) : base(message, inner) {} + } + + /// + /// Exception raised when a precondition fails. + /// + public class PreconditionException : DesignByContractException + { + /// + /// Precondition Exception. + /// + public PreconditionException() {} + /// + /// Precondition Exception. + /// + public PreconditionException(string message) : base(message) {} + /// + /// Precondition Exception. + /// + public PreconditionException(string message, Exception inner) : base(message, inner) {} + } + + /// + /// Exception raised when a postcondition fails. + /// + public class PostconditionException : DesignByContractException + { + /// + /// Postcondition Exception. + /// + public PostconditionException() {} + /// + /// Postcondition Exception. + /// + public PostconditionException(string message) : base(message) {} + /// + /// Postcondition Exception. + /// + public PostconditionException(string message, Exception inner) : base(message, inner) {} + } + + /// + /// Exception raised when an invariant fails. + /// + public class InvariantException : DesignByContractException + { + /// + /// Invariant Exception. + /// + public InvariantException() {} + /// + /// Invariant Exception. + /// + public InvariantException(string message) : base(message) {} + /// + /// Invariant Exception. + /// + public InvariantException(string message, Exception inner) : base(message, inner) {} + } + + /// + /// Exception raised when an assertion fails. + /// + public class AssertionException : DesignByContractException + { + /// + /// Assertion Exception. + /// + public AssertionException() {} + /// + /// Assertion Exception. + /// + public AssertionException(string message) : base(message) {} + /// + /// Assertion Exception. + /// + public AssertionException(string message, Exception inner) : base(message, inner) {} + } + + #endregion // Exception classes + +} // End Design By Contract diff --git a/Svelto.ECS.asmdef b/Svelto.ECS.asmdef new file mode 100644 index 0000000..df4f03a --- /dev/null +++ b/Svelto.ECS.asmdef @@ -0,0 +1,10 @@ +{ + "name": "Svelto.ECS", + "references": [ + "Svelto.Common" + ], + "optionalUnityReferences": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false +} \ No newline at end of file diff --git a/Svelto.ECS/EnginesRoot.Entities.cs b/Svelto.ECS/EnginesRoot.Entities.cs index 8c02da9..daf07eb 100644 --- a/Svelto.ECS/EnginesRoot.Entities.cs +++ b/Svelto.ECS/EnginesRoot.Entities.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using DBC; using Svelto.ECS.Internal; #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR @@ -148,7 +147,7 @@ namespace Svelto.ECS void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID) { - Check.Require(fromGroupID != toGroupID, + DBC.ECS.Check.Require(fromGroupID != toGroupID, "can't move an entity to the same group where it already belongs to"); var entityegid = new EGID(entityID, fromGroupID); diff --git a/Svelto.ECS/EntityDescriptor.cs b/Svelto.ECS/EntityDescriptor.cs index 8a48dc3..1fdb54f 100644 --- a/Svelto.ECS/EntityDescriptor.cs +++ b/Svelto.ECS/EntityDescriptor.cs @@ -30,7 +30,7 @@ namespace Svelto.ECS public DynamicEntityDescriptorInfo(FasterList extraEntityViews) { - Check.Require(extraEntityViews.Count > 0, + DBC.ECS.Check.Require(extraEntityViews.Count > 0, "don't use a DynamicEntityDescriptorInfo if you don't need to use extra EntityViews"); var defaultEntityViewsToBuild = EntityDescriptorTemplate.Info.entityViewsToBuild; diff --git a/Svelto.ECS/EntityViewBuilder.cs b/Svelto.ECS/EntityViewBuilder.cs index 4fba8b9..cc57327 100644 --- a/Svelto.ECS/EntityViewBuilder.cs +++ b/Svelto.ECS/EntityViewBuilder.cs @@ -49,7 +49,7 @@ namespace Svelto.ECS if (needsReflection == true) { - DBC.Check.Require(implementors != null, "Implementors not found while building an EntityView"); + DBC.ECS.Check.Require(implementors != null, "Implementors not found while building an EntityView"); T lentityView; EntityView.BuildEntityView(entityID, out lentityView); diff --git a/Svelto.ECS/Extensions/Unity/GenericEntityDescriptorHolder.cs b/Svelto.ECS/Extensions/Unity/GenericEntityDescriptorHolder.cs index db7e9f7..bf48b5e 100644 --- a/Svelto.ECS/Extensions/Unity/GenericEntityDescriptorHolder.cs +++ b/Svelto.ECS/Extensions/Unity/GenericEntityDescriptorHolder.cs @@ -5,7 +5,7 @@ namespace Svelto.ECS UnityEngine.MonoBehaviour , IEntityDescriptorHolder where T: class, IEntityDescriptor, new() { - public EntityDescriptorInfo RetrieveDescriptor() + public EntityDescriptorInfo RetrieveDescriptorInfo() { return EntityDescriptorTemplate.Info; } diff --git a/Svelto.ECS/IEntityDescriptorHolder.cs b/Svelto.ECS/IEntityDescriptorHolder.cs index e16ca4e..6b5dac5 100644 --- a/Svelto.ECS/IEntityDescriptorHolder.cs +++ b/Svelto.ECS/IEntityDescriptorHolder.cs @@ -2,6 +2,6 @@ namespace Svelto.ECS { public interface IEntityDescriptorHolder { - EntityDescriptorInfo RetrieveDescriptor(); + EntityDescriptorInfo RetrieveDescriptorInfo(); } } \ No newline at end of file diff --git a/Svelto.ECS/IEntityFactory.cs b/Svelto.ECS/IEntityFactory.cs index d1039f5..46cb2b3 100644 --- a/Svelto.ECS/IEntityFactory.cs +++ b/Svelto.ECS/IEntityFactory.cs @@ -42,7 +42,6 @@ namespace Svelto.ECS /// /// EntityStructInitializer BuildEntity(int entityID, int groupID, object[] implementors) where T:class, IEntityDescriptor, new(); - EntityStructInitializer BuildEntity(EGID egid, object[] implementors) where T:class, IEntityDescriptor, new(); diff --git a/Svelto.ECS/IEntityViewsDB.cs b/Svelto.ECS/IEntityViewsDB.cs index ac7973b..0a3b1cd 100644 --- a/Svelto.ECS/IEntityViewsDB.cs +++ b/Svelto.ECS/IEntityViewsDB.cs @@ -1,4 +1,3 @@ -using System; using Svelto.DataStructures; using Svelto.Utilities; @@ -6,19 +5,36 @@ namespace Svelto.ECS { public interface IEntityViewsDB { - //to use with EntityViews + /// + /// All the EntityView related methods are left for back compatibility, but + /// shouldn't be used anymore. Always pick EntityViewStruct or EntityStruct + /// over EntityView + /// ReadOnlyCollectionStruct QueryEntityViews() where T : class, IEntityStruct; + /// + /// All the EntityView related methods are left for back compatibility, but + /// shouldn't be used anymore. Always pick EntityViewStruct or EntityStruct + /// over EntityView + /// ReadOnlyCollectionStruct QueryEntityViews(int group) where T : class, IEntityStruct; + /// + /// All the EntityView related methods are left for back compatibility, but + /// shouldn't be used anymore. Always pick EntityViewStruct or EntityStruct + /// over EntityView + /// + bool TryQueryEntityView(EGID egid, out T entityView) where T : class, IEntityStruct; + /// + /// All the EntityView related methods are left for back compatibility, but + /// shouldn't be used anymore. Always pick EntityViewStruct or EntityStruct + /// over EntityView + /// + T QueryEntityView(EGID egid) where T : class, IEntityStruct; //to use with EntityViews, EntityStructs and EntityViewStructs - T[] QueryEntities(out int count) where T : IEntityStruct; + T[] QueryEntities(out int count) where T : IEntityStruct; T[] QueryEntities(int group, out int count) where T : IEntityStruct; T[] QueryEntities(EGID entityGID, out uint index) where T : IEntityStruct; - //to use with EntityViews - bool TryQueryEntityView(EGID egid, out T entityView) where T : class, IEntityStruct; - T QueryEntityView(EGID egid) where T : class, IEntityStruct; - //to use with EntityViews, EntityStructs and EntityViewStructs void ExecuteOnEntity(EGID egid, ref W value, ActionRef action) where T : IEntityStruct; void ExecuteOnEntity(EGID egid, ActionRef action) where T : IEntityStruct; diff --git a/Svelto.ECS/Sequencer.cs b/Svelto.ECS/Sequencer.cs index 49948b9..2d72cb4 100644 --- a/Svelto.ECS/Sequencer.cs +++ b/Svelto.ECS/Sequencer.cs @@ -35,12 +35,15 @@ namespace Svelto.ECS void Step(ref T token, C condition); } + public interface IEnumStep:IStep + { + void Step(ref T token, Enum condition); + } + public interface ISequencer { void Next(IEngine engine, ref T param); - void Next(IEngine engine, ref T param, int condition); - void Next(IEngine engine, ref T param, C condition) where C : struct, IConvertible; } @@ -65,6 +68,16 @@ namespace Svelto.ECS for (int i = 0; i < steps.Length; i++) ((IStep)steps[i]).Step(ref param, condition); } + + public void Next(IEngine engine, ref T param, Enum condition) + { + int branch = Convert.ToInt32(condition); + var steps = (_steps[engine] as Dictionary)[branch]; + + if (steps != null) + for (int i = 0; i < steps.Length; i++) + ((IEnumStep)steps[i]).Step(ref param, condition); + } public void Next(IEngine engine, ref T param, C condition) where C:struct,IConvertible {