-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Saeed Barari
committed
Jul 16, 2023
0 parents
commit 91146ea
Showing
15 changed files
with
477 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
using System.Runtime.CompilerServices; | ||
|
||
// for editor scripts | ||
[assembly: InternalsVisibleTo( "BinjectEditor" )] |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Runtime.CompilerServices; | ||
using UnityEngine; | ||
|
||
namespace Binject { | ||
/// <summary> | ||
/// A container for dependencies. You can use contexts to group dependencies. | ||
/// </summary> | ||
[DisallowMultipleComponent] | ||
[AddComponentMenu( "Binject/Binject Context" )] | ||
public sealed class BContext : MonoBehaviour { | ||
[SerializeReference] | ||
internal List<IBDependency> dependencies = new( 16 ); | ||
readonly HashSet<Type> _dependencyTypes = new( 16 ); | ||
|
||
void Awake() { | ||
SyncDependencyTypes(); | ||
} | ||
|
||
#if UNITY_EDITOR | ||
void OnValidate() { | ||
for (int i = 0; i < dependencies.Count - 1; i++) | ||
for (int j = i + 1; j < dependencies.Count; j++) | ||
if (dependencies[i].GetType() == dependencies[j].GetType()) | ||
dependencies.RemoveAt( j-- ); | ||
} | ||
|
||
#endif | ||
|
||
void OnEnable() => BManager.AddContext( this ); | ||
void OnDisable() => BManager.RemoveContext( this ); | ||
|
||
[MethodImpl( MethodImplOptions.AggressiveInlining )] | ||
void SyncDependencyTypes() { | ||
for (int i = 0; i < dependencies.Count; i++) | ||
_dependencyTypes.Add( dependencies[i].GetType() ); | ||
} | ||
|
||
/// <summary> | ||
/// Binds a dependency to this context. If one with the same type already exists, the new one will override | ||
/// the old one. | ||
/// </summary> | ||
public void Bind(IBDependency dependency) { | ||
if (_dependencyTypes.Add( dependency.GetType() )) { | ||
// new type | ||
dependencies.Add( dependency ); | ||
} | ||
else { | ||
// override previous of same type | ||
for (int i = 0; i < dependencies.Count; i++) { | ||
if (dependencies[i].GetType() == dependency.GetType()) { | ||
dependencies[i] = dependency; | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Binds a dependency from this context. | ||
/// </summary> | ||
public void Unbind<T>() where T : IBDependency { | ||
if (_dependencyTypes.Remove( typeof(T) )) { | ||
for (int i = 0; i < dependencies.Count; i++) { | ||
if (dependencies[i].GetType() == typeof(T)) { | ||
dependencies.RemoveAt( i ); | ||
return; | ||
} | ||
} | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Checks if this context has a dependency of type <see cref="T"/>. | ||
/// </summary> | ||
public bool HasDependency<T>() where T : unmanaged, IBDependency => _dependencyTypes.Contains( typeof(T) ); | ||
|
||
/// <summary> | ||
/// Returns the dependency of type <see cref="T"/> if it exists, otherwise returns default. | ||
/// </summary> | ||
public T GetDependency<T>() where T : unmanaged, IBDependency { | ||
if (HasDependency<T>()) | ||
for (int i = 0; i < dependencies.Count; i++) | ||
if (dependencies[i].GetType() == typeof(T)) | ||
return (T)dependencies[i]; | ||
return default; | ||
} | ||
|
||
/// <summary> | ||
/// Without checking if it exists, returns the dependency of type <see cref="T"/>. If not found, returns default. | ||
/// Slightly faster than <see cref="GetDependency{T}"/> if you already know that the dependency exists, but | ||
/// using <see cref="HasDependency{T}"/> and this method together is slightly slower than a single | ||
/// <see cref="GetDependency{T}"/> call. | ||
/// </summary> | ||
public T GetDependencyNoCheck<T>() where T : unmanaged, IBDependency { | ||
for (int i = 0; i < dependencies.Count; i++) | ||
if (dependencies[i].GetType() == typeof(T)) | ||
return (T)dependencies[i]; | ||
return default; | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
using System.Collections.Generic; | ||
using System.Runtime.CompilerServices; | ||
using UnityEngine; | ||
|
||
namespace Binject { | ||
public static class BManager { | ||
static readonly List<BContext> _contexts = new List<BContext>( 16 ); | ||
static int _rootContextIndex; | ||
|
||
/// <summary> | ||
/// Finds the context holding the required dependencies of type <see cref="T"/> compatible with the given | ||
/// <see cref="Transform"/>. returns null if not found any. | ||
/// </summary> | ||
[MethodImpl( MethodImplOptions.AggressiveInlining)] | ||
public static BContext FindContext<T>(Transform transform) where T : unmanaged, IBDependency { | ||
|
||
[MethodImpl( MethodImplOptions.AggressiveInlining)] | ||
bool isTheCorrectContext(int i) { | ||
return _contexts[i].transform == transform && _contexts[i].HasDependency<T>(); | ||
} | ||
|
||
do { | ||
for (int i = 0; i < _contexts.Count; i++) | ||
if (isTheCorrectContext( i )) return _contexts[i]; | ||
|
||
if (!transform.parent && transform != _contexts[_rootContextIndex].transform) { | ||
// root context check | ||
if (isTheCorrectContext( _rootContextIndex )) return _contexts[_rootContextIndex]; | ||
} | ||
transform = transform.parent; | ||
} while (transform); | ||
|
||
return null; | ||
} | ||
|
||
#region Helper Functions | ||
|
||
/// <summary> | ||
/// Returns the dependency of type <see cref="T"/> from a compatible context. returns default if not found any. | ||
/// </summary> | ||
[MethodImpl( MethodImplOptions.AggressiveInlining)] | ||
public static T GetDependency<T>(Transform transform) where T : unmanaged, IBDependency { | ||
var context = FindContext<T>( transform ); | ||
if (context == null) return default; | ||
return context.GetDependencyNoCheck<T>(); | ||
} | ||
|
||
/// <summary> | ||
/// Checks if the dependency of type <see cref="T"/> exists in a compatible context. | ||
/// </summary> | ||
[MethodImpl( MethodImplOptions.AggressiveInlining )] | ||
public static bool DependencyExists<T>(Transform transform) where T : unmanaged, IBDependency { | ||
var context = FindContext<T>( transform ); | ||
return context != null; | ||
} | ||
|
||
/// <summary> | ||
/// Returns dependencies of the given type from a compatible context. for each dependency, returns default | ||
/// if not found any. | ||
/// </summary> | ||
[MethodImpl( MethodImplOptions.AggressiveInlining )] | ||
public static (T1, T2) GetDependencies<T1, T2>(Transform transform) | ||
where T1 : unmanaged, IBDependency | ||
where T2 : unmanaged, IBDependency | ||
{ | ||
return (GetDependency<T1>( transform ), GetDependency<T2>( transform )); | ||
} | ||
|
||
/// <inheritdoc cref="GetDependencies{T1,T2}(UnityEngine.Transform)"/> | ||
[MethodImpl( MethodImplOptions.AggressiveInlining )] | ||
public static (T1, T2, T3) GetDependencies<T1, T2, T3>(Transform transform) | ||
where T1 : unmanaged, IBDependency | ||
where T2 : unmanaged, IBDependency | ||
where T3 : unmanaged, IBDependency | ||
{ | ||
return (GetDependency<T1>( transform ), GetDependency<T2>( transform ), GetDependency<T3>( transform )); | ||
} | ||
|
||
/// <inheritdoc cref="GetDependencies{T1,T2}(UnityEngine.Transform)"/> | ||
[MethodImpl( MethodImplOptions.AggressiveInlining )] | ||
public static (T1, T2, T3, T4) GetDependencies<T1, T2, T3, T4>(Transform transform) | ||
where T1 : unmanaged, IBDependency | ||
where T2 : unmanaged, IBDependency | ||
where T3 : unmanaged, IBDependency | ||
where T4 : unmanaged, IBDependency | ||
{ | ||
return (GetDependency<T1>( transform ), GetDependency<T2>( transform ), GetDependency<T3>( transform ), GetDependency<T4>( transform )); | ||
} | ||
|
||
/// <inheritdoc cref="GetDependencies{T1,T2}(UnityEngine.Transform)"/> | ||
[MethodImpl( MethodImplOptions.AggressiveInlining )] | ||
public static (T1, T2, T3, T4, T5) GetDependencies<T1, T2, T3, T4, T5>(Transform transform) | ||
where T1 : unmanaged, IBDependency | ||
where T2 : unmanaged, IBDependency | ||
where T3 : unmanaged, IBDependency | ||
where T4 : unmanaged, IBDependency | ||
where T5 : unmanaged, IBDependency | ||
{ | ||
return (GetDependency<T1>( transform ), GetDependency<T2>( transform ), GetDependency<T3>( transform ), GetDependency<T4>( transform ), GetDependency<T5>( transform )); | ||
} | ||
|
||
#endregion | ||
|
||
#region Helper Extensions | ||
|
||
/// <inheritdoc cref="GetDependency{T}(UnityEngine.Transform)"/> | ||
[MethodImpl( MethodImplOptions.AggressiveInlining )] | ||
public static T GetDependency<T>(this Component component) where T : unmanaged, IBDependency { | ||
return GetDependency<T>( component.transform ); | ||
} | ||
|
||
/// <inheritdoc cref="DependencyExists{T}(UnityEngine.Transform)"/> | ||
[MethodImpl (MethodImplOptions.AggressiveInlining )] | ||
public static bool DependencyExists<T>(this Component component) where T : unmanaged, IBDependency { | ||
return DependencyExists<T>( component.transform ); | ||
} | ||
|
||
/// <inheritdoc cref="GetDependencies{T1,T2}(UnityEngine.Transform)"/> | ||
[MethodImpl (MethodImplOptions.AggressiveInlining )] | ||
public static void GetDependencies<T1, T2>(this Component component, out T1 t1, out T2 t2) | ||
where T1 : unmanaged, IBDependency | ||
where T2 : unmanaged, IBDependency | ||
{ | ||
(t1, t2) = GetDependencies<T1, T2>( component.transform ); | ||
} | ||
|
||
/// <inheritdoc cref="GetDependencies{T1,T2}(UnityEngine.Transform)"/> | ||
[MethodImpl (MethodImplOptions.AggressiveInlining )] | ||
public static void GetDependencies<T1, T2, T3>(this Component component, out T1 t1, out T2 t2, out T3 t3) | ||
where T1 : unmanaged, IBDependency | ||
where T2 : unmanaged, IBDependency | ||
where T3 : unmanaged, IBDependency | ||
{ | ||
(t1, t2, t3) = GetDependencies<T1, T2, T3>( component.transform ); | ||
} | ||
|
||
/// <inheritdoc cref="GetDependencies{T1,T2}(UnityEngine.Transform)"/> | ||
[MethodImpl (MethodImplOptions.AggressiveInlining )] | ||
public static void GetDependencies<T1, T2, T3, T4>(this Component component, out T1 t1, out T2 t2, out T3 t3, out T4 t4) | ||
where T1 : unmanaged, IBDependency | ||
where T2 : unmanaged, IBDependency | ||
where T3 : unmanaged, IBDependency | ||
where T4 : unmanaged, IBDependency | ||
{ | ||
(t1, t2, t3, t4) = GetDependencies<T1, T2, T3, T4>( component.transform ); | ||
} | ||
|
||
/// <inheritdoc cref="GetDependencies{T1,T2}(UnityEngine.Transform)"/> | ||
[MethodImpl (MethodImplOptions.AggressiveInlining )] | ||
public static void GetDependencies<T1, T2, T3, T4, T5>(this Component component, out T1 t1, out T2 t2, out T3 t3, out T4 t4, out T5 t5) | ||
where T1 : unmanaged, IBDependency | ||
where T2 : unmanaged, IBDependency | ||
where T3 : unmanaged, IBDependency | ||
where T4 : unmanaged, IBDependency | ||
where T5 : unmanaged, IBDependency | ||
{ | ||
(t1, t2, t3, t4, t5) = GetDependencies<T1, T2, T3, T4, T5>( component.transform ); | ||
} | ||
|
||
#endregion | ||
|
||
|
||
internal static void AddContext(BContext context) { | ||
_contexts.Add( context ); | ||
UpdateRootContext( new HashSet<int> { _contexts.Count - 1 } ); | ||
} | ||
|
||
internal static void RemoveContext(BContext context) { | ||
var ind = _contexts.IndexOf( context ); | ||
_contexts.RemoveAt( ind ); | ||
} | ||
|
||
|
||
/// <summary> | ||
/// Sorts contexts based on their hierarchy depth and index. | ||
/// </summary> | ||
static void UpdateRootContext(HashSet<int> dirties) { | ||
int rootContextHierarchyIndex = -1; | ||
for (int i = 0; i < _contexts.Count; i++) { | ||
var ind = GetHierarchyIndex( _contexts[i].transform ); | ||
if (rootContextHierarchyIndex < ind) { | ||
rootContextHierarchyIndex = ind; | ||
_rootContextIndex = i; | ||
} | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Returns the index of which the transform will show up in hierarchy if everything is expanded | ||
/// </summary> | ||
[MethodImpl( MethodImplOptions.AggressiveInlining )] | ||
static int GetHierarchyIndex(Transform transform) { | ||
int c = 0; | ||
do { | ||
c += transform.GetSiblingIndex(); | ||
transform = transform.parent; | ||
} while (transform.parent); | ||
|
||
return c; | ||
} | ||
|
||
|
||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
{ | ||
"name": "Binject", | ||
"rootNamespace": "", | ||
"references": [], | ||
"includePlatforms": [], | ||
"excludePlatforms": [], | ||
"allowUnsafeCode": false, | ||
"overrideReferences": false, | ||
"precompiledReferences": [], | ||
"autoReferenced": true, | ||
"defineConstraints": [], | ||
"versionDefines": [], | ||
"noEngineReferences": false | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.