Skip to content

Commit 37a20ed

Browse files
committed
add result types and trait instantiation from pointer
1 parent d7d2c23 commit 37a20ed

File tree

7 files changed

+294
-19
lines changed

7 files changed

+294
-19
lines changed

src/generators/opaque_struct_generator.py

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def __init__(self) -> None:
1313
template = template_handle.read()
1414
self.template = template
1515

16-
def generate_opaque_struct(self, struct_name, struct_details, all_type_details = {}):
16+
def generate_opaque_struct(self, struct_name, struct_details, all_type_details={}):
1717
# method_names = ['openChannel', 'closeChannel']
1818
# native_method_names = ['ChannelHandler_openChannel', 'ChannelHandler_closeChannel']
1919

@@ -34,11 +34,15 @@ def generate_opaque_struct(self, struct_name, struct_details, all_type_details =
3434
passed_argument_name = argument_name
3535
constructor_argument_conversion_method = None
3636

37-
if current_argument_details.rust_obj is not None and current_argument_details.rust_obj.startswith('LDK') and current_argument_details.swift_type.startswith('['):
37+
if (argument_name == '' or argument_name is None) and current_argument_details.swift_type == 'Void' and len(constructor_details['argument_types']) == 1:
38+
break
39+
40+
if current_argument_details.rust_obj is not None and current_argument_details.rust_obj.startswith(
41+
'LDK') and current_argument_details.swift_type.startswith('['):
3842
constructor_argument_conversion_method = f'let converted_{argument_name} = Bindings.new_{current_argument_details.rust_obj}(array: {argument_name})'
3943
constructor_argument_prep += constructor_argument_conversion_method
4044
passed_argument_name = f'converted_{argument_name}'
41-
elif current_argument_details.rust_obj == 'LDK'+current_argument_details.swift_type:
45+
elif current_argument_details.rust_obj == 'LDK' + current_argument_details.swift_type:
4246
passed_argument_name += '.cOpaqueStruct!'
4347

4448
swift_arguments.append(f'{argument_name}: {current_argument_details.swift_type}')
@@ -53,7 +57,12 @@ def generate_opaque_struct(self, struct_name, struct_details, all_type_details =
5357
mutating_output_file_contents = mutating_output_file_contents.replace(
5458
'self.cOpaqueStruct = OpaqueStructType(',
5559
f'self.cOpaqueStruct = {constructor_native_name}(')
56-
60+
else:
61+
# remove the default constructor template
62+
constructor_template_regex = re.compile(
63+
"(\/\* DEFAULT_CONSTRUCTOR_START \*\/\n)(.*)(\n[\t ]*\/\* DEFAULT_CONSTRUCTOR_END \*\/)",
64+
flags=re.MULTILINE | re.DOTALL)
65+
mutating_output_file_contents = constructor_template_regex.sub('', mutating_output_file_contents)
5766

5867
# REGULAR METHODS START
5968

@@ -77,19 +86,26 @@ def generate_opaque_struct(self, struct_name, struct_details, all_type_details =
7786
current_method_name = current_native_method_name[len(method_prefix):]
7887

7988
current_replacement = method_template
89+
is_clone_method = current_method_details['is_clone']
8090

81-
if current_method_details['return_type'].rust_obj is not None and current_method_details['return_type'].rust_obj.startswith('LDK') and current_method_details['return_type'].swift_type.startswith('['):
91+
if current_method_details['return_type'].rust_obj is not None and current_method_details[
92+
'return_type'].rust_obj.startswith('LDK') and current_method_details[
93+
'return_type'].swift_type.startswith('['):
8294
return_type_wrapper_prefix = f'Bindings.{current_method_details["return_type"].rust_obj}_to_array(byteType: '
8395
return_type_wrapper_suffix = ')'
84-
current_replacement = current_replacement.replace('return OpaqueStructType_methodName(native_arguments)', f'return {return_type_wrapper_prefix}OpaqueStructType_methodName(native_arguments){return_type_wrapper_suffix}')
85-
elif current_method_details['return_type'].rust_obj == 'LDK' + current_method_details['return_type'].swift_type:
96+
current_replacement = current_replacement.replace(
97+
'return OpaqueStructType_methodName(native_arguments)',
98+
f'return {return_type_wrapper_prefix}OpaqueStructType_methodName(native_arguments){return_type_wrapper_suffix}')
99+
elif current_method_details['return_type'].rust_obj == 'LDK' + current_method_details[
100+
'return_type'].swift_type and not is_clone_method:
86101
return_type_wrapper_prefix = f'{current_method_details["return_type"].swift_type}(pointer: '
87102
return_type_wrapper_suffix = ')'
88-
current_replacement = current_replacement.replace('return OpaqueStructType_methodName(native_arguments)', f'return {return_type_wrapper_prefix}OpaqueStructType_methodName(native_arguments){return_type_wrapper_suffix}')
103+
current_replacement = current_replacement.replace(
104+
'return OpaqueStructType_methodName(native_arguments)',
105+
f'return {return_type_wrapper_prefix}OpaqueStructType_methodName(native_arguments){return_type_wrapper_suffix}')
89106

90107
current_replacement = current_replacement.replace('func methodName(', f'func {current_method_name}(')
91108

92-
is_clone_method = current_method_details['is_clone']
93109
if is_clone_method:
94110
current_replacement = current_replacement.replace('OpaqueStructType_methodName(',
95111
f'{swift_struct_name}(pointer: {current_native_method_name}(')
@@ -149,7 +165,6 @@ def generate_opaque_struct(self, struct_name, struct_details, all_type_details =
149165

150166
struct_methods += '\n' + current_replacement + '\n'
151167

152-
153168
# DESTRUCTOR START
154169
if struct_details.free_method is not None:
155170
# fill constructor details
@@ -186,15 +201,13 @@ def generate_opaque_struct(self, struct_name, struct_details, all_type_details =
186201
passed_argument_name = 'self.cOpaqueStruct!'
187202
native_arguments.append(f'{passed_argument_name}')
188203

189-
190204
struct_methods += f'''
191205
\n\tdeinit {{
192206
{native_call_prep}
193207
\n\t {free_native_name}({', '.join(native_arguments)})
194208
\n\t}}
195209
'''
196210

197-
198211
mutating_output_file_contents = mutating_output_file_contents.replace('class OpaqueStructName {',
199212
f'class {swift_struct_name} {{')
200213
mutating_output_file_contents = mutating_output_file_contents.replace('init(pointer: OpaqueStructType',
@@ -204,7 +217,6 @@ def generate_opaque_struct(self, struct_name, struct_details, all_type_details =
204217
mutating_output_file_contents = method_template_regex.sub(f'\g<1>{struct_methods}\g<3>',
205218
mutating_output_file_contents)
206219

207-
208220
# store the output
209221
output_path = f'{Config.OUTPUT_DIRECTORY_PATH}/structs/{swift_struct_name}.swift'
210222
output_directory = os.path.dirname(output_path)

src/generators/result_generator.py

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
import re
2+
import os
3+
4+
from config import Config
5+
6+
7+
class ResultGenerator:
8+
9+
def __init__(self) -> None:
10+
super().__init__()
11+
template_path = f'{os.path.dirname(__file__)}/../../templates/ResultTemplate.swift'
12+
with open(template_path, 'r') as template_handle:
13+
template = template_handle.read()
14+
self.template = template
15+
16+
def generate_result(self, struct_name, struct_details, all_type_details={}):
17+
# method_names = ['openChannel', 'closeChannel']
18+
# native_method_names = ['ChannelHandler_openChannel', 'ChannelHandler_closeChannel']
19+
20+
swift_struct_name = struct_name[3:]
21+
22+
mutating_output_file_contents = self.template
23+
24+
# CONSTRUCTOR START
25+
if struct_details.constructor_method is not None:
26+
# fill constructor details
27+
constructor_details = struct_details.constructor_method
28+
constructor_native_name = constructor_details['name']['native']
29+
swift_arguments = []
30+
native_arguments = []
31+
constructor_argument_prep = ''
32+
for current_argument_details in constructor_details['argument_types']:
33+
argument_name = current_argument_details.var_name
34+
passed_argument_name = argument_name
35+
constructor_argument_conversion_method = None
36+
37+
if current_argument_details.rust_obj is not None and current_argument_details.rust_obj.startswith(
38+
'LDK') and current_argument_details.swift_type.startswith('['):
39+
constructor_argument_conversion_method = f'let converted_{argument_name} = Bindings.new_{current_argument_details.rust_obj}(array: {argument_name})'
40+
constructor_argument_prep += constructor_argument_conversion_method
41+
passed_argument_name = f'converted_{argument_name}'
42+
elif current_argument_details.rust_obj == 'LDK' + current_argument_details.swift_type:
43+
passed_argument_name += '.cOpaqueStruct!'
44+
45+
swift_arguments.append(f'{argument_name}: {current_argument_details.swift_type}')
46+
native_arguments.append(f'{passed_argument_name}')
47+
48+
mutating_output_file_contents = mutating_output_file_contents.replace('swift_constructor_arguments',
49+
', '.join(swift_arguments))
50+
mutating_output_file_contents = mutating_output_file_contents.replace('/* NATIVE_CONSTRUCTOR_PREP */',
51+
constructor_argument_prep)
52+
mutating_output_file_contents = mutating_output_file_contents.replace('native_constructor_arguments',
53+
', '.join(native_arguments))
54+
mutating_output_file_contents = mutating_output_file_contents.replace(
55+
'self.cOpaqueStruct = ResultType(',
56+
f'self.cOpaqueStruct = {constructor_native_name}(')
57+
else:
58+
# remove the default constructor template
59+
constructor_template_regex = re.compile(
60+
"(\/\* DEFAULT_CONSTRUCTOR_START \*\/\n)(.*)(\n[\t ]*\/\* DEFAULT_CONSTRUCTOR_END \*\/)",
61+
flags=re.MULTILINE | re.DOTALL)
62+
mutating_output_file_contents = constructor_template_regex.sub('', mutating_output_file_contents)
63+
64+
# REGULAR METHODS START
65+
66+
method_template_regex = re.compile(
67+
"(\/\* RESULT_METHODS_START \*\/\n)(.*)(\n[\t ]*\/\* RESULT_METHODS_END \*\/)",
68+
flags=re.MULTILINE | re.DOTALL)
69+
method_template = method_template_regex.search(mutating_output_file_contents).group(2)
70+
71+
method_prefix = swift_struct_name + '_'
72+
struct_methods = ''
73+
74+
# fill templates
75+
for current_method_details in struct_details.methods:
76+
current_native_method_name = current_method_details['name']['native']
77+
current_method_name = current_method_details['name']['swift']
78+
current_return_type = current_method_details['return_type'].swift_type
79+
# current_rust_return_type = current_method_details['return_type'].rust_obj
80+
81+
# if current_rust_return_type in all_type_details and all_type_details[current_rust_return_type].type.name == 'UNITARY_ENUM':
82+
# current_return_type = current_rust_return_type
83+
current_method_name = current_native_method_name[len(method_prefix):]
84+
85+
current_replacement = method_template
86+
is_clone_method = current_method_details['is_clone']
87+
88+
if current_method_details['return_type'].rust_obj is not None and current_method_details[
89+
'return_type'].rust_obj.startswith('LDK') and current_method_details[
90+
'return_type'].swift_type.startswith('['):
91+
return_type_wrapper_prefix = f'Bindings.{current_method_details["return_type"].rust_obj}_to_array(byteType: '
92+
return_type_wrapper_suffix = ')'
93+
current_replacement = current_replacement.replace(
94+
'return ResultType_methodName(native_arguments)',
95+
f'return {return_type_wrapper_prefix}ResultType_methodName(native_arguments){return_type_wrapper_suffix}')
96+
elif current_method_details['return_type'].rust_obj == 'LDK' + current_method_details[
97+
'return_type'].swift_type and not is_clone_method:
98+
return_type_wrapper_prefix = f'{current_method_details["return_type"].swift_type}(pointer: '
99+
return_type_wrapper_suffix = ')'
100+
current_replacement = current_replacement.replace(
101+
'return ResultType_methodName(native_arguments)',
102+
f'return {return_type_wrapper_prefix}ResultType_methodName(native_arguments){return_type_wrapper_suffix}')
103+
104+
current_replacement = current_replacement.replace('func methodName(', f'func {current_method_name}(')
105+
106+
if is_clone_method:
107+
current_replacement = current_replacement.replace('ResultType_methodName(',
108+
f'{swift_struct_name}(pointer: {current_native_method_name}(')
109+
else:
110+
current_replacement = current_replacement.replace('ResultType_methodName(',
111+
f'{current_native_method_name}(')
112+
# replace arguments
113+
swift_arguments = []
114+
native_arguments = []
115+
native_call_prep = ''
116+
for current_argument_details in current_method_details['argument_types']:
117+
pass_instance = False
118+
argument_name = current_argument_details.var_name
119+
passed_argument_name = argument_name
120+
if argument_name == 'this_ptr':
121+
pass_instance = True
122+
123+
if current_argument_details.is_ptr:
124+
passed_argument_name = argument_name + 'Pointer'
125+
requires_mutability = not current_argument_details.is_const
126+
127+
mutability_infix = ''
128+
129+
if pass_instance:
130+
argument_name = 'self'
131+
if requires_mutability:
132+
argument_name = '&' + argument_name
133+
mutability_infix = 'Mutable'
134+
# let managerPointer = withUnsafePointer(to: self.cChannelManager!) { (pointer: UnsafePointer<LDKChannelManager>) in
135+
# pointer
136+
# }
137+
# the \n\t will add a bunch of extra lines, but this file will be easier to read
138+
current_prep = f'''
139+
\n\t let {passed_argument_name} = withUnsafe{mutability_infix}Pointer(to: {argument_name}.cOpaqueStruct!) {{ (pointer: Unsafe{mutability_infix}Pointer<{current_argument_details.rust_obj}>) in
140+
\n\t\t pointer
141+
\n\t }}
142+
'''
143+
native_call_prep += current_prep
144+
145+
if not pass_instance:
146+
swift_arguments.append(f'{argument_name}: {current_argument_details.swift_type}')
147+
148+
# native_arguments.append(f'{passed_argument_name}')
149+
if current_argument_details.rust_obj == 'LDK' + current_argument_details.swift_type and not current_argument_details.is_ptr:
150+
native_arguments.append(f'{passed_argument_name}.cOpaqueStruct!')
151+
else:
152+
native_arguments.append(f'{passed_argument_name}')
153+
154+
current_replacement = current_replacement.replace('swift_arguments', ', '.join(swift_arguments))
155+
if is_clone_method:
156+
# add closing parenthesis that could not be added further up in the clone initializer
157+
current_replacement = current_replacement.replace('native_arguments', ', '.join(native_arguments) + ')')
158+
else:
159+
current_replacement = current_replacement.replace('native_arguments', ', '.join(native_arguments))
160+
current_replacement = current_replacement.replace('/* NATIVE_CALL_PREP */', native_call_prep)
161+
current_replacement = current_replacement.replace('-> Void {', f'-> {current_return_type} {{')
162+
163+
struct_methods += '\n' + current_replacement + '\n'
164+
165+
# DESTRUCTOR START
166+
if struct_details.free_method is not None:
167+
# fill constructor details
168+
free_method_details = struct_details.free_method
169+
free_native_name = free_method_details['name']['native']
170+
native_call_prep = ''
171+
native_arguments = []
172+
for current_argument_details in free_method_details['argument_types']:
173+
pass_instance = False
174+
argument_name = current_argument_details.var_name
175+
passed_argument_name = argument_name
176+
if argument_name.startswith('this_'):
177+
pass_instance = True
178+
179+
if current_argument_details.is_ptr:
180+
passed_argument_name = argument_name + 'Pointer'
181+
requires_mutability = not current_argument_details.is_const
182+
183+
mutability_infix = ''
184+
185+
if pass_instance:
186+
argument_name = 'self'
187+
if requires_mutability:
188+
argument_name = '&' + argument_name
189+
mutability_infix = 'Mutable'
190+
191+
current_prep = f'''
192+
\n\t let {passed_argument_name} = withUnsafe{mutability_infix}Pointer(to: {argument_name}.cOpaqueStruct!) {{ (pointer: Unsafe{mutability_infix}Pointer<{current_argument_details.rust_obj}>) in
193+
\n\t\t pointer
194+
\n\t }}
195+
'''
196+
native_call_prep += current_prep
197+
elif pass_instance:
198+
passed_argument_name = 'self.cOpaqueStruct!'
199+
native_arguments.append(f'{passed_argument_name}')
200+
201+
struct_methods += f'''
202+
\n\tdeinit {{
203+
{native_call_prep}
204+
\n\t {free_native_name}({', '.join(native_arguments)})
205+
\n\t}}
206+
'''
207+
208+
mutating_output_file_contents = mutating_output_file_contents.replace('class ResultName {',
209+
f'class {swift_struct_name} {{')
210+
mutating_output_file_contents = mutating_output_file_contents.replace('init(pointer: ResultType',
211+
f'init(pointer: {struct_name}')
212+
mutating_output_file_contents = mutating_output_file_contents.replace('var cOpaqueStruct: ResultType?',
213+
f'var cOpaqueStruct: {struct_name}?')
214+
mutating_output_file_contents = method_template_regex.sub(f'\g<1>{struct_methods}\g<3>',
215+
mutating_output_file_contents)
216+
217+
# store the output
218+
output_path = f'{Config.OUTPUT_DIRECTORY_PATH}/results/{swift_struct_name}.swift'
219+
output_directory = os.path.dirname(output_path)
220+
if not os.path.exists(output_directory):
221+
os.makedirs(output_directory)
222+
with open(output_path, "w") as f:
223+
f.write(mutating_output_file_contents)

src/generators/trait_generator.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,11 @@ def generate_trait(self, struct_name, struct_details):
7777
swift_callbacks += '\n' + current_swift_callback_replacement + '\n'
7878

7979
trait_file = self.template.replace('class TraitName {', f'class {swift_struct_name} {{')
80-
trait_file = trait_file.replace('var cTrait: TraitType?',
81-
f'var cTrait: {struct_name}?')
82-
trait_file = trait_file.replace('self.cTrait = TraitType(',
83-
f'self.cTrait = {struct_name}(')
80+
trait_file = trait_file.replace('init(pointer: TraitType', f'init(pointer: {struct_name}')
81+
trait_file = trait_file.replace('var cOpaqueStruct: TraitType?',
82+
f'var cOpaqueStruct: {struct_name}?')
83+
trait_file = trait_file.replace('self.cOpaqueStruct = TraitType(',
84+
f'self.cOpaqueStruct = {struct_name}(')
8485
trait_file = trait_file.replace('native_callback_instantiation_arguments', ', '.join(instantiation_arguments))
8586
trait_file = native_callback_template_regex.sub(f'\g<1>{native_callbacks}\g<3>', trait_file)
8687
trait_file = swift_callback_template_regex.sub(f'\g<1>{swift_callbacks}\g<3>', trait_file)

src/sdk_generator.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from lightning_header_parser import LightningHeaderParser
22
from generators.opaque_struct_generator import OpaqueStructGenerator
33
from generators.tuple_generator import TupleGenerator
4+
from generators.result_generator import ResultGenerator
45
from generators.trait_generator import TraitGenerator
56
from generators.util_generators.vector_generator import VectorGenerator
67
from generators.util_generators.byte_array_generator import ByteArrayGenerator
@@ -49,6 +50,14 @@ def generate_tuple_wrappers(parser: LightningHeaderParser):
4950
current_tuple_details = parser.type_details[current_tuple]
5051
tuple_generator.generate_tuple(current_tuple, current_tuple_details, all_type_details=parser.type_details)
5152

53+
def generate_result_wrappers(parser: LightningHeaderParser):
54+
result_generator = ResultGenerator()
55+
56+
results = parser.result_types
57+
for current_result in results:
58+
current_result_details = parser.type_details[current_result]
59+
result_generator.generate_result(current_result, current_result_details, all_type_details=parser.type_details)
60+
5261

5362
def generate_trait_placeholders(parser: LightningHeaderParser):
5463
trait_generator = TraitGenerator()
@@ -64,6 +73,7 @@ def generate_sdk():
6473
generate_binding_methods(parser)
6574
generate_opaque_struct_wrappers(parser)
6675
generate_tuple_wrappers(parser)
76+
generate_result_wrappers(parser)
6777
generate_trait_placeholders(parser)
6878

6979

templates/OpaqueStructTemplate.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ class OpaqueStructName {
22

33
var cOpaqueStruct: OpaqueStructType?;
44

5+
/* DEFAULT_CONSTRUCTOR_START */
56
init(swift_constructor_arguments) {
67
/* NATIVE_CONSTRUCTOR_PREP */
78
self.cOpaqueStruct = OpaqueStructType(native_constructor_arguments)
89
}
10+
/* DEFAULT_CONSTRUCTOR_END */
911

1012
init(pointer: OpaqueStructType){
1113
self.cOpaqueStruct = pointer

0 commit comments

Comments
 (0)