Skip to content

Commit

Permalink
fix(clrcore-v2): Coroutine.Run, OutString cast, and transparency issue
Browse files Browse the repository at this point in the history
* Only run Coroutine.Run(...) functions directly when we're on the main thread, otherwise we run it next frame.
* Fix return type of Coroutine.Run<T>(...);
* Move OutString -> CString conversion operator.
* Fix CAS transparency issue with EventHandlerSet's + operator for `Delegate` types (don't know why SecAnnotate didn't pick up on this).
  • Loading branch information
thorium-cfx committed Jul 1, 2023
1 parent 530c18f commit b6c387a
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 22 deletions.
39 changes: 26 additions & 13 deletions code/client/clrcore-v2/Coroutine/CoroutineMethods.cs
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System;
using System.Runtime.InteropServices;
using System.Threading;

namespace CitizenFX.Core
{
Expand Down Expand Up @@ -208,25 +209,37 @@ public static Coroutine Schedule(Action function, ulong delay, ulong iterations,
#region Run

/// <summary>
/// Runs given function directly and allows the caller to await it.
/// Runs given function on the main thread; will be scheduled if we're not on the main thread, otherwise it'll be run directly.
/// </summary>
/// <param name="function">Function to run</param>
/// <returns>Awaitable <see cref="Coroutine"/></returns>
public static Coroutine Run(Func<Coroutine> function) => function();

/// <inheritdoc cref="Run(Func{Coroutine})"/>
public static Coroutine Run(Action function)
{
function();
return Completed();
if (Thread.CurrentThread == Scheduler.MainThread)
{
function();
return Completed();
}

return RunNextFrame(function);
}

/// <summary>
/// Runs given function directly and allows the caller to await it.
/// </summary>
/// <param name="function">Function to run</param>
/// <returns>Awaitable <see cref="Coroutine"/></returns>
public static Coroutine Run<TResult>(Func<Coroutine<TResult>> function) => function();
/// <inheritdoc cref="Run(Action)"/>
public static Coroutine Run(Func<Coroutine> function)
{
return Thread.CurrentThread == Scheduler.MainThread
? function()
: RunNextFrame(function);
}

/// <returns>Awaitable <see cref="Coroutine{T}"/></returns>
/// <inheritdoc cref="Run(Action)"/>
public static Coroutine<T> Run<T>(Func<Coroutine<T>> function)
{
return Thread.CurrentThread == Scheduler.MainThread
? function()
: RunNextFrame(function);
}

/// <summary>
/// Runs given function next frame and allows the caller to await it.
Expand Down Expand Up @@ -260,7 +273,7 @@ public static Coroutine RunNextFrame(Action function)
/// Runs given function directly and allows the caller to await it.
/// </summary>
/// <param name="function">Function to run</param>
/// <returns>Awaitable <see cref="Coroutine"/></returns>
/// <returns>Awaitable <see cref="Coroutine{T}"/></returns>
public static Coroutine<T> RunNextFrame<T>(Func<Coroutine<T>> function)
{
var coroutine = new Coroutine<T>();
Expand Down
2 changes: 1 addition & 1 deletion code/client/clrcore-v2/Interop/EventsManager.cs
Expand Up @@ -181,7 +181,7 @@ public EventHandlerSet Remove(Delegate deleg)
/// <param name="entry">this event handler set</param>
/// <param name="deleg">delegate to register</param>
/// <returns>itself</returns>
public static EventHandlerSet operator +(EventHandlerSet entry, Delegate deleg) => entry.Add(Func.Create(deleg.Target, deleg.Method));
public static EventHandlerSet operator +(EventHandlerSet entry, Delegate deleg) => entry.Add(Func.Create(deleg));

/// <summary>
/// Unregister an event handler
Expand Down
7 changes: 7 additions & 0 deletions code/client/clrcore-v2/Interop/Types/CString.cs
Expand Up @@ -315,6 +315,13 @@ public int CompareTo(CString other)
/// <param name="str">null-terminated c-string</param>
public static explicit operator string(CString str) => str?.ToString();

/// <summary>
/// Copy <see cref="OutString"/> into a null-terminated c-string
/// </summary>
/// <param name="str">OutString to copy</param>
/// <!-- Does put a dependency on OutString -->
public static implicit operator CString(OutString str) => str.ToCString();

#endregion

#region ASCII operations
Expand Down
14 changes: 6 additions & 8 deletions code/client/clrcore-v2/Native/Types/OutString.cs
Expand Up @@ -19,13 +19,6 @@ namespace CitizenFX.Core
[SecuritySafeCritical]
public static unsafe implicit operator string(in OutString str) => Marshal.PtrToStringAnsi((IntPtr)str.data);

/// <summary>
/// A managed string that holds a copy of the unmanaged ANSI string. If ptr is null, the method returns a null string.
/// </summary>
/// <param name="str"></param>
[SecuritySafeCritical]
public static unsafe explicit operator CString(in OutString str) => CString.Create(str.data);

/// <summary>
/// A managed byte[] that holds a copy of the unmanaged ANSI string. If ptr is null, the method returns a null string.
/// </summary>
Expand All @@ -50,7 +43,12 @@ namespace CitizenFX.Core

public override string ToString() => (string)this;

public CString ToCString() => (CString)this;
/// <summary>
/// Creates a null terminated C-string out of the returned string
/// </summary>
/// <returns>null terminated C-string</returns>
[SecuritySafeCritical]
public unsafe CString ToCString() => CString.Create(data);

/// <summary>
/// Retrieves a substring from this string. Starting at the specified <paramref name="startIndex"/> in strides of <see cref="byte"/>
Expand Down

0 comments on commit b6c387a

Please sign in to comment.