-
Notifications
You must be signed in to change notification settings - Fork 358
Open
Labels
feature request 📬A request for new changes to improve functionalityA request for new changes to improve functionality
Description
Overview
Adding RefTuple<...>
types would allow ref structs to be used in tuples.
API breakdown
public ref struct RefTuple<T1,T2>
where T1 : allows ref struct
where T2 : allows ref struct
{
public RefTuple(T1 t1, T2 t2);
public T1 Item1 { get; set; }
public T2 Item2 { get; set; }
public readonly void Deconstruct(out T1 item1, out T2 item2);
}
Usage example
This is an example using pattern matching to select a reference to a field, and a paired value. The ref
is wrapped in a Ref<T>
, which as a ref struct
cannot be stored in a normal tuple or ValueTuple
.
// Get reference to selected register argument
RefTuple<Ref<GPRegister>, RegisterSet> pair = target switch
{
// General Purpose Registers
Argument.RS => new(new(ref _rs), RegisterSet.GeneralPurpose),
Argument.RT => new(new(ref _rt), RegisterSet.GeneralPurpose),
Argument.RD => new(new(ref _rd), RegisterSet.GeneralPurpose),
// Float Registers
Argument.FS => new(new(ref _rs), RegisterSet.FloatingPoints),
Argument.FT => new(new(ref _rt), RegisterSet.FloatingPoints),
Argument.FD => new(new(ref _rd), RegisterSet.FloatingPoints),
// RT Register for coprocessors
Argument.RT_Numbered => new(new(ref _rt), RegisterSet.Numbered),
// Invalid target type
_ => throw new ArgumentOutOfRangeException($"Argument of type '{target}' attempted to parse as a register.")
};
(Ref<GPRegister> regRef, RegisterSet set) = pair;
ref GPRegister reg = ref regRef.Value;
Breaking change?
No
Alternatives
For the code above, here's what it looks like using a switch statement instead of a switch expression.
// Get reference to selected register argument
ref GPRegister reg = ref _rs;
RegisterSet set = RegisterSet.GeneralPurpose;
switch (target)
{
// General Purpose Registers
case Argument.RS:
reg = ref _rs;
break;
case Argument.RT:
reg = ref _rt;
break;
case Argument.RD:
reg = ref _rd;
break;
// Float Registers
case Argument.FS:
reg = ref _rs;
set = RegisterSet.FloatingPoints;
break;
case Argument.FT:
reg = ref _rt;
set = RegisterSet.FloatingPoints;
break;
case Argument.FD:
reg = ref _rd;
set = RegisterSet.FloatingPoints;
break;
// RT Register for coprocessors
case Argument.RT_Numbered:
reg = ref _rt;
set = RegisterSet.Numbered;
break;
// Invalid target type
default:
return ThrowHelper.ThrowArgumentOutOfRangeException<bool>($"Argument of type '{target}' attempted to parse as a register.");
}
Perfectly legitimate code, but the pattern matching is much more convenient to read.
Additional context
This requires .NET 9 and C# version 13
Help us help you
Yes, I'd like to be assigned to work on this item
Metadata
Metadata
Assignees
Labels
feature request 📬A request for new changes to improve functionalityA request for new changes to improve functionality