Skip to content

Commit

Permalink
feat: Add ability to configure if marhsal and/or unmarshal method sho…
Browse files Browse the repository at this point in the history
…uld be generated when using TSMessageAttribute + generated TS messages are now in the same namespace as where they are declared in C#
  • Loading branch information
dr1rrb committed Jan 21, 2022
1 parent aa3e6e9 commit 6459564
Show file tree
Hide file tree
Showing 50 changed files with 1,013 additions and 907 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -568,5 +568,17 @@ public static string GetFullyQualifiedType(this ITypeSymbol type)

return type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
}

public static TypedConstant? FindNamedArg(this AttributeData attribute, string argName)
=> attribute.NamedArguments is { IsDefaultOrEmpty: false } args
&& args.FirstOrDefault(arg => arg.Key == argName) is { Key: not null } arg
? arg.Value
: null;

public static T? GetNamedValue<T>(this AttributeData attribute, string argName)
where T : Enum
=> attribute.FindNamedArg(argName) is { IsNull: false, Kind: TypedConstantKind.Enum } arg && arg.Type!.Name == typeof(T).Name
? (T)arg.Value!
: default(T?);
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using Microsoft.CodeAnalysis;
using Uno.Extensions;
using Uno.Foundation.Interop;
using Uno.UI.SourceGenerators.Helpers;
using Uno.Roslyn;

Expand All @@ -32,7 +34,6 @@ public void Initialize(GeneratorInitializationContext context)

public void Execute(GeneratorExecutionContext context)
{

if (!DesignTimeHelper.IsDesignTime(context))
{
_bindingsPaths = context.GetMSBuildPropertyValue("TSBindingsPath")?.ToString();
Expand All @@ -59,52 +60,69 @@ where _sourceAssemblies.Contains(sym.Name)

internal void GenerateTSMarshallingLayouts(IEnumerable<IModuleSymbol> modules)
{
var messageTypes = from module in modules
from type in GetNamespaceTypes(module)
where (
type.FindAttributeFlattened(_interopMessageSymbol) != null
&& type.TypeKind == TypeKind.Struct
)
select type;
var messages = from module in modules
from type in GetNamespaceTypes(module)
let attr = type.FindAttributeFlattened(_interopMessageSymbol)
where attr is not null && type.TypeKind is TypeKind.Struct
select (type, attr);

messageTypes = messageTypes.ToArray();
messages = messages.ToArray();

foreach (var messageType in messageTypes)
foreach (var message in messages)
{
var packValue = GetStructPack(messageType);
var packValue = GetStructPack(message.type);

var sb = new IndentedStringBuilder();

sb.AppendLineInvariant($"/* {nameof(TSBindingsGenerator)} Generated code -- this code is regenerated on each build */");

using (sb.BlockInvariant($"class {messageType.Name}"))
var ns = message.type.ContainingNamespace.ToDisplayString();
if (message.type.ContainingType?.Name?.Contains("WindowManagerInterop", StringComparison.OrdinalIgnoreCase) ?? false)
{
sb.AppendLineInvariant($"/* Pack={packValue} */");
// For backward compatibility, we include the namespace only for types that are not part of the WindowsManagerInterop.
// We should include the namespace for all messages, but it would require to update all usages.
ns = null;
}

foreach (var field in messageType.GetFields())
using (ns is null ? null : sb.BlockInvariant($"namespace {ns}"))
{
using (sb.BlockInvariant($"{(ns is null ? "": "export ")}class {message.type.Name}"))
{
sb.AppendLineInvariant($"public {field.Name} : {GetTSFieldType(field.Type)};");
}
sb.AppendLineInvariant($"/* Pack={packValue} */");

if (messageType.Name.EndsWith("Params") || messageType.Name.EndsWith("EventArgs"))
{
GenerateUnmarshaler(messageType, sb, packValue);
}
foreach (var field in message.type.GetFields())
{
sb.AppendLineInvariant($"public {field.Name} : {GetTSFieldType(field.Type)};");
}

if (messageType.Name.EndsWith("Return") || messageType.Name.EndsWith("EventArgs"))
{
GenerateMarshaler(messageType, sb, packValue);
if (message.attr.GetNamedValue<CodeGeneration>(nameof(TSInteropMessageAttribute.UnMarshaller)) switch
{
CodeGeneration.Enabled => true,
CodeGeneration.Disabled => false,
_ => message.type.Name.EndsWith("Params") || message.type.Name.EndsWith("EventArgs"),
})
{
GenerateUnmarshaler(message.type, sb, packValue);
}

if (message.attr.GetNamedValue<CodeGeneration>(nameof(TSInteropMessageAttribute.Marshaller)) switch
{
CodeGeneration.Enabled => true,
CodeGeneration.Disabled => false,
_ => message.type.Name.EndsWith("Return") || message.type.Name.EndsWith("EventArgs"),
})
{
GenerateMarshaler(message.type, sb, packValue);
}
}
}

var outputPath = Path.Combine(_bindingsPaths, $"{messageType.Name}.ts");
var outputPath = Path.Combine(_bindingsPaths, $"{(ns is null ? "" : ns.Replace('.', '_') + "_")}{message.type.Name}.ts");

var fileExists = File.Exists(outputPath);
var output = sb.ToString();

if (
(fileExists && File.ReadAllText(outputPath) != output)
|| !fileExists)
if (!fileExists || File.ReadAllText(outputPath) != output)
{
File.WriteAllText(outputPath, output);
}
Expand Down Expand Up @@ -361,6 +379,7 @@ private int GetNativeFieldSize(IFieldSymbol field)
SymbolEqualityComparer.Default.Equals(field.Type, _intPtrSymbol) ||
field.Type.SpecialType is SpecialType.System_Single ||
field.Type.SpecialType is SpecialType.System_Boolean ||
field.Type.SpecialType is SpecialType.System_Byte ||
field.Type is IArrayTypeSymbol
)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@
<Compile Include="..\..\Uno.UI\UI\Xaml\XamlFilePathHelper.shared.cs">
<Link>Helpers\XamlFilePathHelper.shared.cs</Link>
</Compile>
<Compile Include="..\..\Uno.Foundation.Runtime.WebAssembly\Interop\TSInteropMessageAttribute.wasm.cs">
<Link>TSBindings\TSInteropMessageAttribute.cs</Link>
</Compile>
</ItemGroup>

<Import Project="..\..\Uno.Foundation\Uno.Core.Extensions\Uno.Core.Extensions.props" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ namespace Uno.Foundation.Interop
/// </summary>
[AttributeUsage(AttributeTargets.Struct, AllowMultiple = false)]
public class TSInteropMessageAttribute : Attribute
{
public CodeGeneration Marshaller { get; set; }

public CodeGeneration UnMarshaller { get; set; }
}

public enum CodeGeneration
{
Auto = 0,
Enabled = 1,
Disabled = 256,
}
}
49 changes: 27 additions & 22 deletions src/Uno.UI.Wasm.Tests/WasmScripts/UnitTests.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,35 @@ declare class TSBindingsTests {
When_NullArrayOfStrings(pParams: number, pReturn: number): boolean;
When_ArrayOfNullStrings(pParams: number, pReturn: number): boolean;
}
declare class GenericReturn {
Value: string;
marshal(pData: number): void;
declare namespace SamplesApp.UnitTests.TSBindings {
class GenericReturn {
Value: string;
marshal(pData: number): void;
}
}
declare class When_ArrayOfIntParams {
MyArray_Length: number;
MyArray: Array<number>;
static unmarshal(pData: number): When_ArrayOfIntParams;
declare namespace SamplesApp.UnitTests.TSBindings {
class When_ArrayOfIntParams {
MyArray_Length: number;
MyArray: Array<number>;
static unmarshal(pData: number): When_ArrayOfIntParams;
}
}
declare class When_ArrayOfStringParams {
MyArray_Length: number;
MyArray: Array<string>;
static unmarshal(pData: number): When_ArrayOfStringParams;
declare namespace SamplesApp.UnitTests.TSBindings {
class When_ArrayOfStringsParams {
MyArray_Length: number;
MyArray: Array<string>;
static unmarshal(pData: number): When_ArrayOfStringsParams;
}
}
declare class When_ArrayOfStringsParams {
MyArray_Length: number;
MyArray: Array<string>;
static unmarshal(pData: number): When_ArrayOfStringsParams;
declare namespace SamplesApp.UnitTests.TSBindings {
class When_IntPtrParams {
Id: number;
static unmarshal(pData: number): When_IntPtrParams;
}
}
declare class When_IntPtrParams {
Id: number;
static unmarshal(pData: number): When_IntPtrParams;
}
declare class When_SingleStringParams {
MyString: string;
static unmarshal(pData: number): When_SingleStringParams;
declare namespace SamplesApp.UnitTests.TSBindings {
class When_SingleStringParams {
MyString: string;
static unmarshal(pData: number): When_SingleStringParams;
}
}

0 comments on commit 6459564

Please sign in to comment.