Skip to content

Commit 56fb059

Browse files
chore: rename documentation
1 parent 22616a5 commit 56fb059

1 file changed

Lines changed: 178 additions & 0 deletions

File tree

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
# Native Functions Integration
2+
3+
This document describes how to integrate custom Python logic into generated Rune code using **Native Functions**.
4+
5+
## Overview
6+
7+
Native functions allow developers to provide custom Python implementations for Rune functions that either cannot be expressed in the Rosetta DSL or require optimized low-level logic.
8+
9+
**Audience**: Rune developers and Python engineers.
10+
11+
**Contents**:
12+
13+
- Definitions of native functions.
14+
- Mechanism of registration and execution.
15+
- Implementation guidelines and troubleshooting.
16+
- Comprehensive end-to-end example.
17+
18+
---
19+
20+
## 1. What are Native Functions
21+
22+
A function is treated as "Native" by the Python generator if:
23+
24+
- It is explicitly annotated with `[codeImplementation]`. (**Recommended**)
25+
- It has no operations (assignment or `add` statements) in its body.
26+
27+
### Exclusions
28+
29+
**Enum Dispatchers** (functions that act as switchboards) are excluded from the implicit "no operations" rule. Dispatcher headers are always generated as `match` statements in Python and will not be treated as native unless explicitly annotated with `[codeImplementation]`.
30+
31+
---
32+
33+
## 2. Integration Mechanism
34+
35+
### Registration and Discovery
36+
37+
The generated code includes a call to `rune_attempt_register_native_functions` during module initialization. This mechanism:
38+
39+
1. Identifies all functions flagged as native during generation.
40+
2. Attempts to dynamically import these functions from a specific package prefix (default: `rune.native`).
41+
3. Registers successfully imported callables in a global registry.
42+
43+
### The Runtime Hook
44+
45+
At runtime, the generated code uses `rune_execute_native`. If a function is called but no implementation was successfully registered, it will raise a `NotImplementedError` listing the available functions.
46+
47+
---
48+
49+
## 3. Implementation Guidelines
50+
51+
### Naming Contract
52+
53+
The Python module must follow the **Fully Qualified Name (FQN)** of the Rune definition, prefixed with `rune.native`.
54+
55+
- **Rune Namespace**: `rosetta_dsl.test.functions`
56+
- **Rune Function**: `RoundToNearest`
57+
- **Expected Python Import Path**: `rune.native.rosetta_dsl.test.functions.RoundToNearest`
58+
59+
### Signature Matching
60+
61+
The Python function must accept exactly the same parameters as defined in Rune, in the same order. Use Python type hints where possible to maintain type safety.
62+
63+
### Troubleshooting
64+
65+
If your native function is not being called:
66+
67+
1. **Check Logs**: The initialization logic logs a `WARNING` if a module import fails or if the attribute found is not callable.
68+
2. **Verify Package**: Ensure your native code is installed in the current environment (e.g., via `pip install -e`).
69+
3. **Implicit Init**: Ensure all directories in your path contain an `__init__.py` file to be treated as a valid Python package.
70+
71+
---
72+
73+
## 4. End-to-End Example
74+
75+
### A. Rune Definition
76+
77+
**File**: `NativeFunctionTest.rosetta`
78+
79+
```rosetta
80+
namespace rosetta_dsl.test.functions
81+
82+
// This function is implemented in Python
83+
func RoundToNearest:
84+
[codeImplementation]
85+
inputs:
86+
value number (1..1)
87+
digits int (1..1)
88+
roundingMode RoundingModeEnum (1..1)
89+
output:
90+
roundedValue number (1..1)
91+
92+
// This function is a regular Rune function that calls the native one
93+
func RoundUp:
94+
inputs:
95+
value number (1..1)
96+
digits int (1..1)
97+
output:
98+
roundedValue number (1..1)
99+
set roundedValue:
100+
RoundToNearest(value, digits, RoundingModeEnum -> Up)
101+
```
102+
103+
### B. Native Python Implementation
104+
105+
Place your logic in the directory structure matching the namespace.
106+
107+
**File**: `src/rune/native/rosetta_dsl/test/functions/RoundToNearest.py`
108+
109+
```python
110+
from decimal import Decimal
111+
from rosetta_dsl.test.functions.RoundingModeEnum import RoundingModeEnum
112+
113+
def RoundToNearest(value: Decimal, digits: int, roundingMode: RoundingModeEnum) -> Decimal:
114+
"""
115+
Implementation using Python's Decimal quantization.
116+
"""
117+
decimal_mode = "ROUND_UP" if roundingMode == RoundingModeEnum.UP else "ROUND_DOWN"
118+
quantifier = Decimal("1").scaleb(-digits)
119+
return value.quantize(quantifier, rounding=decimal_mode)
120+
```
121+
122+
### C. Packaging and Installation
123+
124+
Use a standard Python packaging tool (like `setuptools`) to make the `rune.native` namespace discoverable.
125+
126+
**File**: `pyproject.toml`
127+
128+
```toml
129+
[project]
130+
name = "rosetta-dsl-native-functions"
131+
version = "0.1.0"
132+
133+
[tool.setuptools.packages.find]
134+
where = ["src"]
135+
```
136+
137+
**Installation Command**:
138+
139+
```bash
140+
python -m pip install -e .
141+
```
142+
143+
### D. Invocation and Generated Code
144+
145+
When Rune generates code for a native function, it creates a wrapper that handles the bridge to your Python implementation using `rune_execute_native`.
146+
147+
**Note**: The examples are mocked up and do not include the complete code.
148+
149+
**Generated Wrapper for `RoundToNearest`**:
150+
151+
```python
152+
@replaceable
153+
@validate_call
154+
def RoundToNearest(value: Decimal, digits: int, roundingMode: RoundingModeEnum) -> Decimal:
155+
# ... initialization ...
156+
roundedValue = rune_execute_native('rosetta_dsl.test.functions.RoundToNearest', value, digits, roundingMode)
157+
158+
return roundedValue
159+
```
160+
161+
Other generated functions call this wrapper just like any other function:
162+
163+
**Generated Code for `RoundUp`**:
164+
165+
```python
166+
@replaceable
167+
@validate_call
168+
def RoundUp(value: Decimal, digits: int) -> Decimal:
169+
# ...
170+
# Calls the native wrapper defined above
171+
roundedValue = RoundToNearest(value, digits, RoundingModeEnum.UP)
172+
173+
return roundedValue
174+
```
175+
176+
#### Runtime Behaviour
177+
178+
Once installed, any Rune code calling `RoundUp` will automatically route through the native bridge to your Python logic.

0 commit comments

Comments
 (0)