Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
Saeed Barari committed Jul 16, 2023
0 parents commit 91146ea
Show file tree
Hide file tree
Showing 15 changed files with 477 additions and 0 deletions.
4 changes: 4 additions & 0 deletions AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
using System.Runtime.CompilerServices;

// for editor scripts
[assembly: InternalsVisibleTo( "BinjectEditor" )]
3 changes: 3 additions & 0 deletions AssemblyInfo.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

103 changes: 103 additions & 0 deletions BContext.cs
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;
}
}
}
3 changes: 3 additions & 0 deletions BContext.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

204 changes: 204 additions & 0 deletions BManager.cs
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;
}


}
}
3 changes: 3 additions & 0 deletions BManager.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions Binject.asmdef
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
}
7 changes: 7 additions & 0 deletions Binject.asmdef.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Editor.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 91146ea

Please sign in to comment.