Files
RobustToolbox/Robust.Shared/Toolshed/ToolshedManager.Types.cs
Leon Friedrich 9af119f57a Toolshed Rejig (#5455)
* Toolshed Rejig

* shorten hint string

* Try fix conflicts. Ill make with work later

* bodge

* Fix ProtoIdTypeParser assert

* comment

* AllEntities

* Remove more linq from WhereCommand

* better help strings

* Add ContainsCommand

* loc strings

* Add contains command description

* Add $self variable

* Errors for writing to readonly variables

* A
2024-12-21 17:49:11 +11:00

107 lines
2.7 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Robust.Shared.Toolshed.TypeParsers;
namespace Robust.Shared.Toolshed;
public sealed partial class ToolshedManager
{
// If this gets updated, ensure that GetTransformer() is also updated
internal bool IsTransformableTo(Type left, Type right)
{
if (left.IsAssignableToGeneric(right, this))
return true;
var asType = typeof(IAsType<>).MakeGenericType(right);
if (left.GetInterfaces().Contains(asType))
{
return true;
}
if (!right.IsGenericType(typeof(IEnumerable<>)))
return false;
return right.GenericTypeArguments[0] == left;
}
// Autobots, roll out!
// If this gets updated, ensure that IsTransformableTo() is also updated
internal Expression GetTransformer(Type from, Type to, Expression input)
{
if (from.IsAssignableTo(to))
return Expression.Convert(input, to);
var asType = typeof(IAsType<>).MakeGenericType(to);
if (from.GetInterfaces().Contains(asType))
{
// Just call astype 4head
return Expression.Convert(
Expression.Call(input, asType.GetMethod(nameof(IAsType<int>.AsType))!),
to
);
}
if (to.IsGenericType(typeof(IEnumerable<>)))
{
var toInner = to.GenericTypeArguments[0];
var tys = new[] {toInner};
return Expression.Convert(
Expression.New(
typeof(UnitEnumerable<>).MakeGenericType(tys).GetConstructor(tys)!,
Expression.Convert(input, toInner)
),
to
);
}
if (from.IsAssignableToGeneric(to, this))
return Expression.Convert(input, to);
throw new InvalidCastException();
}
}
internal sealed record UnitEnumerable<T>(T Value) : IEnumerable<T>
{
internal record struct UnitEnumerator(T Value) : IEnumerator<T>
{
private bool _taken = false;
public bool MoveNext()
{
if (_taken)
return false;
_taken = true;
return true;
}
public void Reset()
{
_taken = false;
}
public T Current => Value;
object IEnumerator.Current => Current!;
public void Dispose()
{
}
}
public IEnumerator<T> GetEnumerator()
{
return new UnitEnumerator(Value);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}