Add python constructor+signature, property getters and setters

This commit is contained in:
Caelan Sayler
2025-06-04 16:29:01 +01:00
committed by Caelan
parent 615f1bda5e
commit 4301e5246b
3 changed files with 161 additions and 9 deletions

View File

@@ -1,4 +1,4 @@
using System.Reflection; using System.Reflection;
using HandlebarsDotNet; using HandlebarsDotNet;
var scriptsDir = Assembly.GetEntryAssembly()! var scriptsDir = Assembly.GetEntryAssembly()!
@@ -62,12 +62,8 @@ var types = new List<TypeMap>() {
TypeMap.Primitive("u64", "uint64_t"), TypeMap.Primitive("u64", "uint64_t"),
}.ToDictionary(v => v.rustType, v => v); }.ToDictionary(v => v.rustType, v => v);
var handlebarData = availableStructs.Select(s => new RustStruct_Struct { var handlebarData = availableStructs.Select(s => {
rust_comment = s.DocComment.ToRustComment(), var fields = s.Fields.Select(f => {
cpp_comment = s.DocComment.ToCppComment(),
struct_rust_name = s.Name,
struct_c_name = types[s.Name].interopType,
fields = s.Fields.Select(f => {
var isString = types[f.Type].rustType == "PathBuf" || types[f.Type].rustType == "String"; var isString = types[f.Type].rustType == "PathBuf" || types[f.Type].rustType == "String";
var field = new RustStruct_Field { var field = new RustStruct_Field {
rust_comment = f.DocComment.ToRustComment(), rust_comment = f.DocComment.ToRustComment(),
@@ -83,7 +79,22 @@ var handlebarData = availableStructs.Select(s => new RustStruct_Struct {
field_normal = !f.Vec && !types[f.Type].primitive, field_normal = !f.Vec && !types[f.Type].primitive,
}; };
return field; return field;
}).ToArray(), }).ToArray();
var opt_ordered_fields = fields
.Where(f => !f.field_optional)
.Concat(fields.Where(f => f.field_optional))
.ToArray();
var stru = new RustStruct_Struct {
rust_comment = s.DocComment.ToRustComment(),
cpp_comment = s.DocComment.ToCppComment(),
struct_rust_name = s.Name,
struct_c_name = types[s.Name].interopType,
fields = fields,
opt_ordered_fields = opt_ordered_fields,
};
return stru;
}).ToArray(); }).ToArray();
string rustTypes = Path.Combine(libcppDir, "src", "types.rs"); string rustTypes = Path.Combine(libcppDir, "src", "types.rs");
@@ -99,7 +110,7 @@ Util.ReplaceTextInFile(rustTypes, "RUST_TYPES", rustCTypes.ToString().ReplaceLin
Util.ReplaceTextInFile(rustCppInclude, "CPP_TYPES", cppTypes.ToString().ReplaceLineEndings("\n")); Util.ReplaceTextInFile(rustCppInclude, "CPP_TYPES", cppTypes.ToString().ReplaceLineEndings("\n"));
// --- Python asset.rs generation --- // --- Python asset.rs generation ---
string pythonAssetRs = Path.Combine(scriptsDir, "..", "lib-python", "src", "asset.rs"); string pythonAssetRs = Path.Combine(scriptsDir, "..", "lib-python", "src", "types.rs");
var pythonAssetTemplate = Handlebars.Compile(File.ReadAllText(Path.Combine(templatesDir, "python_asset.hbs"))); var pythonAssetTemplate = Handlebars.Compile(File.ReadAllText(Path.Combine(templatesDir, "python_asset.hbs")));
var pythonAsset = pythonAssetTemplate(handlebarData); var pythonAsset = pythonAssetTemplate(handlebarData);
File.WriteAllText(pythonAssetRs, pythonAsset.ToString().ReplaceLineEndings("\n")); File.WriteAllText(pythonAssetRs, pythonAsset.ToString().ReplaceLineEndings("\n"));
@@ -159,6 +170,7 @@ class RustStruct_Struct
public string rust_comment; public string rust_comment;
public string cpp_comment; public string cpp_comment;
public RustStruct_Field[] fields; public RustStruct_Field[] fields;
public RustStruct_Field[] opt_ordered_fields;
} }
class RustStruct_Field class RustStruct_Field

View File

@@ -9,12 +9,42 @@ use std::path::PathBuf;
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct Py{{struct_rust_name}} { pub struct Py{{struct_rust_name}} {
{{#each fields}} {{#each fields}}
#[pyo3(get, set)]
pub {{field_name}}: {{#if field_vector}}Vec<{{/if}}{{#if field_optional}}Option<{{/if~}} pub {{field_name}}: {{#if field_vector}}Vec<{{/if}}{{#if field_optional}}Option<{{/if~}}
{{~#unless field_primitive_or_system}}Py{{/unless}}{{field_rust_type}} {{~#unless field_primitive_or_system}}Py{{/unless}}{{field_rust_type}}
{{~#if field_optional}}>{{/if}}{{#if field_vector}}>{{/if}}, {{~#if field_optional}}>{{/if}}{{#if field_vector}}>{{/if}},
{{/each}} {{/each}}
} }
#[pymethods]
impl Py{{struct_rust_name}} {
#[new]
#[pyo3(signature = ({{#each opt_ordered_fields}}{{field_name}}{{#if field_optional}} = None{{/if~}}{{#unless @last}}, {{/unless}}{{/each}}))]
fn new(
{{#each opt_ordered_fields}}{{field_name}}: {{#if field_vector}}Vec<{{/if}}{{#if field_optional}}Option<{{/if~}}
{{~#unless field_primitive_or_system}}Py{{/unless}}{{field_rust_type}}
{{~#if field_optional}}>{{/if}}{{#if field_vector}}>{{/if}},
{{/each}}) -> Self {
Self {
{{#each fields}}
{{#if field_vector}}
{{field_name}}: {{field_name}}.into_iter().map(Into::into).collect(),
{{/if}}
{{#if field_primitive}}
{{field_name}}: {{field_name}},
{{/if}}
{{#if field_optional}}
{{field_name}}: {{field_name}}.map(Into::into),
{{else}}
{{#if field_normal}}
{{field_name}}: {{field_name}}.into(),
{{/if}}
{{/if}}
{{/each}}
}
}
}
impl From<{{struct_rust_name}}> for Py{{struct_rust_name}} { impl From<{{struct_rust_name}}> for Py{{struct_rust_name}} {
fn from(value: {{struct_rust_name}}) -> Self { fn from(value: {{struct_rust_name}}) -> Self {
Py{{struct_rust_name}} { Py{{struct_rust_name}} {

View File

@@ -7,14 +7,43 @@ use std::path::PathBuf;
#[pyclass(name = "VelopackLocatorConfig")] #[pyclass(name = "VelopackLocatorConfig")]
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct PyVelopackLocatorConfig { pub struct PyVelopackLocatorConfig {
#[pyo3(get, set)]
pub RootAppDir: PathBuf, pub RootAppDir: PathBuf,
#[pyo3(get, set)]
pub UpdateExePath: PathBuf, pub UpdateExePath: PathBuf,
#[pyo3(get, set)]
pub PackagesDir: PathBuf, pub PackagesDir: PathBuf,
#[pyo3(get, set)]
pub ManifestPath: PathBuf, pub ManifestPath: PathBuf,
#[pyo3(get, set)]
pub CurrentBinaryDir: PathBuf, pub CurrentBinaryDir: PathBuf,
#[pyo3(get, set)]
pub IsPortable: bool, pub IsPortable: bool,
} }
#[pymethods]
impl PyVelopackLocatorConfig {
#[new]
#[pyo3(signature = (RootAppDir, UpdateExePath, PackagesDir, ManifestPath, CurrentBinaryDir, IsPortable))]
fn new(
RootAppDir: PathBuf,
UpdateExePath: PathBuf,
PackagesDir: PathBuf,
ManifestPath: PathBuf,
CurrentBinaryDir: PathBuf,
IsPortable: bool,
) -> Self {
Self {
RootAppDir: RootAppDir.into(),
UpdateExePath: UpdateExePath.into(),
PackagesDir: PackagesDir.into(),
ManifestPath: ManifestPath.into(),
CurrentBinaryDir: CurrentBinaryDir.into(),
IsPortable: IsPortable,
}
}
}
impl From<VelopackLocatorConfig> for PyVelopackLocatorConfig { impl From<VelopackLocatorConfig> for PyVelopackLocatorConfig {
fn from(value: VelopackLocatorConfig) -> Self { fn from(value: VelopackLocatorConfig) -> Self {
PyVelopackLocatorConfig { PyVelopackLocatorConfig {
@@ -44,17 +73,55 @@ impl Into<VelopackLocatorConfig> for PyVelopackLocatorConfig {
#[pyclass(name = "VelopackAsset")] #[pyclass(name = "VelopackAsset")]
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct PyVelopackAsset { pub struct PyVelopackAsset {
#[pyo3(get, set)]
pub PackageId: String, pub PackageId: String,
#[pyo3(get, set)]
pub Version: String, pub Version: String,
#[pyo3(get, set)]
pub Type: String, pub Type: String,
#[pyo3(get, set)]
pub FileName: String, pub FileName: String,
#[pyo3(get, set)]
pub SHA1: String, pub SHA1: String,
#[pyo3(get, set)]
pub SHA256: String, pub SHA256: String,
#[pyo3(get, set)]
pub Size: u64, pub Size: u64,
#[pyo3(get, set)]
pub NotesMarkdown: String, pub NotesMarkdown: String,
#[pyo3(get, set)]
pub NotesHtml: String, pub NotesHtml: String,
} }
#[pymethods]
impl PyVelopackAsset {
#[new]
#[pyo3(signature = (PackageId, Version, Type, FileName, SHA1, SHA256, Size, NotesMarkdown, NotesHtml))]
fn new(
PackageId: String,
Version: String,
Type: String,
FileName: String,
SHA1: String,
SHA256: String,
Size: u64,
NotesMarkdown: String,
NotesHtml: String,
) -> Self {
Self {
PackageId: PackageId.into(),
Version: Version.into(),
Type: Type.into(),
FileName: FileName.into(),
SHA1: SHA1.into(),
SHA256: SHA256.into(),
Size: Size,
NotesMarkdown: NotesMarkdown.into(),
NotesHtml: NotesHtml.into(),
}
}
}
impl From<VelopackAsset> for PyVelopackAsset { impl From<VelopackAsset> for PyVelopackAsset {
fn from(value: VelopackAsset) -> Self { fn from(value: VelopackAsset) -> Self {
PyVelopackAsset { PyVelopackAsset {
@@ -90,12 +157,35 @@ impl Into<VelopackAsset> for PyVelopackAsset {
#[pyclass(name = "UpdateInfo")] #[pyclass(name = "UpdateInfo")]
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct PyUpdateInfo { pub struct PyUpdateInfo {
#[pyo3(get, set)]
pub TargetFullRelease: PyVelopackAsset, pub TargetFullRelease: PyVelopackAsset,
#[pyo3(get, set)]
pub BaseRelease: Option<PyVelopackAsset>, pub BaseRelease: Option<PyVelopackAsset>,
#[pyo3(get, set)]
pub DeltasToTarget: Vec<PyVelopackAsset>, pub DeltasToTarget: Vec<PyVelopackAsset>,
#[pyo3(get, set)]
pub IsDowngrade: bool, pub IsDowngrade: bool,
} }
#[pymethods]
impl PyUpdateInfo {
#[new]
#[pyo3(signature = (TargetFullRelease, DeltasToTarget, IsDowngrade, BaseRelease = None))]
fn new(
TargetFullRelease: PyVelopackAsset,
DeltasToTarget: Vec<PyVelopackAsset>,
IsDowngrade: bool,
BaseRelease: Option<PyVelopackAsset>,
) -> Self {
Self {
TargetFullRelease: TargetFullRelease.into(),
BaseRelease: BaseRelease.map(Into::into),
DeltasToTarget: DeltasToTarget.into_iter().map(Into::into).collect(),
IsDowngrade: IsDowngrade,
}
}
}
impl From<UpdateInfo> for PyUpdateInfo { impl From<UpdateInfo> for PyUpdateInfo {
fn from(value: UpdateInfo) -> Self { fn from(value: UpdateInfo) -> Self {
PyUpdateInfo { PyUpdateInfo {
@@ -121,11 +211,31 @@ impl Into<UpdateInfo> for PyUpdateInfo {
#[pyclass(name = "UpdateOptions")] #[pyclass(name = "UpdateOptions")]
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct PyUpdateOptions { pub struct PyUpdateOptions {
#[pyo3(get, set)]
pub AllowVersionDowngrade: bool, pub AllowVersionDowngrade: bool,
#[pyo3(get, set)]
pub ExplicitChannel: Option<String>, pub ExplicitChannel: Option<String>,
#[pyo3(get, set)]
pub MaximumDeltasBeforeFallback: i32, pub MaximumDeltasBeforeFallback: i32,
} }
#[pymethods]
impl PyUpdateOptions {
#[new]
#[pyo3(signature = (AllowVersionDowngrade, MaximumDeltasBeforeFallback, ExplicitChannel = None))]
fn new(
AllowVersionDowngrade: bool,
MaximumDeltasBeforeFallback: i32,
ExplicitChannel: Option<String>,
) -> Self {
Self {
AllowVersionDowngrade: AllowVersionDowngrade,
ExplicitChannel: ExplicitChannel.map(Into::into),
MaximumDeltasBeforeFallback: MaximumDeltasBeforeFallback,
}
}
}
impl From<UpdateOptions> for PyUpdateOptions { impl From<UpdateOptions> for PyUpdateOptions {
fn from(value: UpdateOptions) -> Self { fn from(value: UpdateOptions) -> Self {
PyUpdateOptions { PyUpdateOptions {