From cc210063a3b0ac2d6ae0f9740ecd0d315a3e0cf4 Mon Sep 17 00:00:00 2001 From: Eric Rodrigues Pires Date: Wed, 12 Nov 2025 11:22:52 +0000 Subject: [PATCH] Start turning into a proper Csharp lib --- duper_uniffi/LICENSE | 1 + duper_uniffi/justfile | 14 +++++++++----- duper_uniffi/uniffi.toml | 2 +- duper_uniffi/csharp/.gitignore | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ duper_uniffi/csharp/Duper.cs | 17 +++++++++++++++++ duper_uniffi/csharp/Duper.csproj | 11 +++++++++++ duper_uniffi/csharp/Duper.nuspec | 20 ++++++++++++++++++++ duper_uniffi/example/.gitignore | 2 -- duper_uniffi/example/Example.cs | 31 ------------------------------- duper_uniffi/example/example.csproj | 13 ------------- duper_uniffi/src/duper.udl | 10 ++++++++-- duper_uniffi/src/lib.rs | 27 ++++++++++++++++++++------- duper_uniffi/example/csharp/.gitignore | 2 ++ duper_uniffi/example/csharp/Example.cs | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ duper_uniffi/example/csharp/example.csproj | 15 +++++++++++++++ 15 file(s) changed, 289 insertion(s)(+), 61 deletion(s)(-) diff --git a/duper_uniffi/LICENSE b/duper_uniffi/LICENSE new file mode 100644 --- /dev/null +++ b/duper_uniffi/LICENSE @@ -0,0 +1,1 @@ +../LICENSE \ No newline at end of file diff --git a/duper_uniffi/justfile b/duper_uniffi/justfile --- a/duper_uniffi/justfile +++ b/duper_uniffi/justfile @@ -1,13 +1,17 @@ default: just --list -build: +bindgen-debug: cargo build - uniffi-bindgen-cs src/duper.udl --config uniffi.toml --out-dir out + uniffi-bindgen-cs src/duper.udl --config uniffi.toml --out-dir csharp/ffi -example: example-cs +bindgen-release: + cargo build --release --target x86_64-unknown-linux-gnu + uniffi-bindgen-cs src/duper.udl --config uniffi.toml --out-dir csharp/ffi -[working-directory: 'example'] +example: bindgen-release example-cs + +[working-directory: 'example/csharp'] example-cs: dotnet build - LD_LIBRARY_PATH="../../target/debug" dotnet run \ No newline at end of file + LD_LIBRARY_PATH="../../../target/x86_64-unknown-linux-gnu/release" dotnet run diff --git a/duper_uniffi/uniffi.toml b/duper_uniffi/uniffi.toml --- a/duper_uniffi/uniffi.toml +++ b/duper_uniffi/uniffi.toml @@ -1,4 +1,4 @@ [bindings.csharp] cdylib_name = "duper_uniffi" -namespace = "Duper" +namespace = "Duper.Ffi" global_methods_class_name = "Duper" diff --git a/duper_uniffi/csharp/.gitignore b/duper_uniffi/csharp/.gitignore new file mode 100644 --- /dev/null +++ b/duper_uniffi/csharp/.gitignore @@ -0,0 +1,135 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.svclog +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# Click-Once directory +publish/ + +# Publish Web Output +*.Publish.xml +*.pubxml +*.azurePubxml + +# NuGet Packages Directory +## TODO: If you have NuGet Package Restore enabled, uncomment the next line +packages/ +## TODO: If the tool you use requires repositories.config, also uncomment the next line +!packages/repositories.config + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +![Ss]tyle[Cc]op.targets +~$* +*~ +*.dbmdl +*.[Pp]ublish.xml + +*.publishsettings + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac desktop service store files +.DS_Store + +_NCrunch* + +ffi/ \ No newline at end of file diff --git a/duper_uniffi/csharp/Duper.cs b/duper_uniffi/csharp/Duper.cs new file mode 100644 --- /dev/null +++ b/duper_uniffi/csharp/Duper.cs @@ -0,0 +1,17 @@ +namespace Duper; + +public class DuperSerializer +{ + public static T? Deserialize(string @input) + { + var parsed = Ffi.Duper.Parse(input, true); + Console.WriteLine(parsed); + Console.WriteLine(typeof(T)); + throw new ApplicationException("Unimplemented"); + } + + public static string Serialize(T @value, bool minify) + { + throw new ApplicationException("Unimplemented"); + } +} diff --git a/duper_uniffi/csharp/Duper.csproj b/duper_uniffi/csharp/Duper.csproj new file mode 100644 --- /dev/null +++ b/duper_uniffi/csharp/Duper.csproj @@ -0,0 +1,11 @@ + + + + net8.0 + enable + enable + enable + true + + + diff --git a/duper_uniffi/csharp/Duper.nuspec b/duper_uniffi/csharp/Duper.nuspec new file mode 100644 --- /dev/null +++ b/duper_uniffi/csharp/Duper.nuspec @@ -0,0 +1,20 @@ + + + + EpicEric.Duper + 0.1.0 + Duper + Eric Rodrigues Pires <eric@eric.dev.br> + MIT + https://duper.dev.br + https://duper.dev.br/logos/duper-200-200.png + false + The format that's super! + Initial release. + Copyright 2025 + Duper encoding format serialization parsing + + + + + diff --git a/duper_uniffi/example/.gitignore b/duper_uniffi/example/.gitignore deleted file mode 100644 --- a/duper_uniffi/example/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -bin/ -obj/ diff --git a/duper_uniffi/example/Example.cs b/duper_uniffi/example/Example.cs deleted file mode 100644 --- a/duper_uniffi/example/Example.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Duper; - -class Example -{ - static void Main(string[] args) - { - var output = Duper.Duper.Parse(@" - UserProfile({ - id: Uuid(""f111c275-b4ce-4392-8e5b-19067ce39b53""), - username: ""EpicEric"", - email: EmailAddress(""eric@duper.dev.br""), - settings: { - ""dark mode"": true, - language: Locale(""pt-BR""), - metadata: null, - }, - score: 120.25, - // Support for bytes, woohoo! - avatar: Png(b64""iVBORw0KGgoAAAANSUhEUgAAAGQ""), - bio: r#""Hello! I'm a super ""duper"" user!""#, - last_logins: [ - (IPv4Address(""192.168.1.100""), Instant('2024-03-20T14:30:00+00:00')), - ], - }) - ", false); - var obj = (DuperValue.Object)output; - var id = (DuperValue.String)obj.value["id"]; - Console.WriteLine(id.value); - Console.WriteLine(Duper.Duper.Serialize(output, true, true, null)); - } -} diff --git a/duper_uniffi/example/example.csproj b/duper_uniffi/example/example.csproj deleted file mode 100644 --- a/duper_uniffi/example/example.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - Exe - net8.0 - enable - enable - true - - - - - - diff --git a/duper_uniffi/src/duper.udl b/duper_uniffi/src/duper.udl --- a/duper_uniffi/src/duper.udl +++ b/duper_uniffi/src/duper.udl @@ -15,10 +15,16 @@ [Error] enum DuperError { "Parse", - "Options", + "SerializeOptions", "InvalidIdentifier", "InvalidObject", "InvalidTemporal", +}; + +dictionary SerializeOptions { + string? indent; + boolean strip_identifiers; + boolean minify; }; namespace duper { @@ -26,5 +32,5 @@ DuperValue parse([ByRef] string input, boolean parse_any); [Throws=DuperError] - string serialize(DuperValue input, boolean strip_identifiers, boolean minify, string? indent); + string serialize(DuperValue input, SerializeOptions? options); }; diff --git a/duper_uniffi/src/lib.rs b/duper_uniffi/src/lib.rs --- a/duper_uniffi/src/lib.rs +++ b/duper_uniffi/src/lib.rs @@ -56,8 +56,8 @@ pub enum DuperError { #[error("Parse error: {0}")] Parse(String), - #[error("Invalid options: {0}")] - Options(&'static str), + #[error("Invalid serialization options: {0}")] + SerializeOptions(&'static str), #[error("Identifier error: {0}")] InvalidIdentifier(#[from] DuperIdentifierTryFromError<'static>), #[error("Object error: {0}")] @@ -79,21 +79,34 @@ Ok(value.accept(&mut UniffiVisitor)) } -pub fn serialize( - value: DuperValue, +pub struct SerializeOptions { + indent: Option, strip_identifiers: bool, minify: bool, - indent: Option, +} + +pub fn serialize( + value: DuperValue, + options: Option, ) -> Result { let value = value.serialize()?; + let SerializeOptions { + indent, + strip_identifiers, + minify, + } = options.unwrap_or(SerializeOptions { + indent: None, + strip_identifiers: false, + minify: false, + }); if let Some(indent) = indent { if minify { - Err(DuperError::Options( + Err(DuperError::SerializeOptions( "Cannot serialize Duper value with both indent and minify options", )) } else { Ok(PrettyPrinter::new(strip_identifiers, indent.as_ref()) - .map_err(DuperError::Options)? + .map_err(DuperError::SerializeOptions)? .pretty_print(value)) } } else { diff --git a/duper_uniffi/example/csharp/.gitignore b/duper_uniffi/example/csharp/.gitignore new file mode 100644 --- /dev/null +++ b/duper_uniffi/example/csharp/.gitignore @@ -0,0 +1,2 @@ +bin/ +obj/ diff --git a/duper_uniffi/example/csharp/Example.cs b/duper_uniffi/example/csharp/Example.cs new file mode 100644 --- /dev/null +++ b/duper_uniffi/example/csharp/Example.cs @@ -0,0 +1,50 @@ +using Duper; + +namespace Example +{ + public class UserProfile + { + public required string @id; + public required string @username; + public required string @email; + public required UserSettings @settings; + public double @score; + public required byte[] @avatar; + public string? @bio; + public required IList<(string, string)> @last_logins; + } + + public class UserSettings + { + public bool DarkMode; + public required string @language; + public Dictionary? @metadata; + } + + public class Example + { + public static void Main(string[] args) + { + UserProfile? userProfile = DuperSerializer.Deserialize(@" + UserProfile({ + id: Uuid(""f111c275-b4ce-4392-8e5b-19067ce39b53""), + username: ""EpicEric"", + email: EmailAddress(""eric@duper.dev.br""), + settings: { + ""dark mode"": true, + language: Locale(""pt-BR""), + metadata: null, + }, + score: 120.25, + // Support for bytes, woohoo! + avatar: Png(b64""iVBORw0KGgoAAAANSUhEUgAAAGQ""), + bio: r#""Hello! I'm a super ""duper"" user!""#, + last_logins: [ + (IPv4Address(""192.168.1.100""), Instant('2024-03-20T14:30:00+00:00')), + ], + })"); + Console.WriteLine(userProfile); + // Console.WriteLine(DuperSerializer.Serialize(userProfile)); + } + } +} diff --git a/duper_uniffi/example/csharp/example.csproj b/duper_uniffi/example/csharp/example.csproj new file mode 100644 --- /dev/null +++ b/duper_uniffi/example/csharp/example.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + enable + enable + true + + + + + + + -- tangled.sh