TinyML inference engine for embedded devices โ Rust no_std core with Python bindings and quantization utilities
Project description
๐ง NANO-RUST-AI
TinyML Inference Engine โ Train in PyTorch, Run on Microcontrollers
Train (PyTorch, GPU) โ Quantize (float32 โ int8) โ Verify (Python) โ Deploy (ESP32/STM32)
๐ฆ Installation
pip install nano-rust-py
That's it. No Rust toolchain needed for using the library. Includes both the Rust inference engine and Python quantization utilities.
import nano_rust_py
print(nano_rust_py.__name__) # โ "nano_rust_py"
For development (modifying Rust source): see Development Setup below.
๐ Quick Start โ 3-Step Example
import nano_rust_py
# Step 1: Create model (input: 4 features, arena: 4KB scratch memory)
model = nano_rust_py.PySequentialModel(input_shape=[4], arena_size=4096)
# Step 2: Add layers with i8 weights
# Dense layer: 4 inputs โ 3 outputs
# weights = [4ร3] matrix flattened, bias = [3] vector
model.add_dense(
weights=[10, -5, 3, 7, -2, 8, -4, 6, 1, 5, -3, 9], # 4ร3 = 12 values
bias=[1, -1, 2] # 3 values
)
model.add_relu()
# Step 3: Run inference
input_data = [100, -50, 30, 70] # i8 values: [-128, 127]
output = model.forward(input_data)
print(output) # โ [15, 0, 22] (i8 values after ReLU)
# Get predicted class
prediction = model.predict(input_data)
print(prediction) # โ 2 (argmax index)
๐ Complete Python API Reference
PySequentialModel โ The Core Model Class
Constructor
model = nano_rust_py.PySequentialModel(
input_shape, # List[int] โ shape of input tensor
arena_size # int โ scratch memory in bytes
)
| Parameter | Type | Description |
|---|---|---|
input_shape |
List[int] |
[N] for 1D, [C, H, W] for 3D (e.g., [1, 28, 28] for MNIST) |
arena_size |
int |
Bytes for intermediate computation. Rule: 2 ร largest_layer_output ร sizeof(i8) |
# 1D input (e.g., sensor features)
model = nano_rust_py.PySequentialModel([128], 4096)
# 3D input (e.g., MNIST image: 1 channel, 28ร28)
model = nano_rust_py.PySequentialModel([1, 28, 28], 32768)
Layer Methods
add_dense(weights, bias) โ Fully-Connected Layer (Frozen)
Weights stored in Flash (0 bytes RAM). Uses simple requantization.
# 4 inputs โ 2 outputs
model.add_dense(
weights=[10, -5, 3, 7, -2, 8], # flat [out ร in] = [2 ร 4] = 8 values
bias=[1, -1] # [out] = 2 values
)
| Parameter | Type | Shape | Description |
|---|---|---|---|
weights |
List[int] |
[out_features ร in_features] |
i8 weight matrix, row-major |
bias |
List[int] |
[out_features] |
i8 bias vector |
Output: out[j] = clamp(ฮฃ(w[j,i] ร x[i]) + bias[j]) requantized to i8
add_dense_with_requant(weights, bias, requant_m, requant_shift) โ Dense with Calibrated Requantization
For high-accuracy inference. Uses TFLite-style (acc ร M) >> shift.
model.add_dense_with_requant(
weights=[10, -5, 3, 7, -2, 8],
bias=[1, -1],
requant_m=1234, # int32 multiplier (from calibration)
requant_shift=15 # uint32 bit-shift (from calibration)
)
| Parameter | Type | Description |
|---|---|---|
requant_m |
int |
Fixed-point multiplier from calibrate_model() |
requant_shift |
int |
Bit-shift from calibrate_model() |
When to use: Always prefer this over
add_dense()when you have calibration data. Accuracy improves from ~85% to ~97%.
add_conv2d(kernel, bias, in_ch, out_ch, kh, kw, stride, padding) โ 2D Convolution (Frozen)
# 1 input channel โ 8 output channels, 3ร3 kernel
model.add_conv2d(
kernel=[...], # [out_ch ร in_ch ร kh ร kw] = 8ร1ร3ร3 = 72 values
bias=[...], # [out_ch] = 8 values
in_ch=1, out_ch=8, kh=3, kw=3,
stride=1, padding=1
)
| Parameter | Type | Description |
|---|---|---|
kernel |
List[int] |
i8 kernel, shape [out_ch ร in_ch ร kh ร kw], row-major |
bias |
List[int] |
i8 bias, shape [out_ch] |
in_ch |
int |
Input channels |
out_ch |
int |
Output channels (number of filters) |
kh, kw |
int |
Kernel height and width |
stride |
int |
Stride (typically 1 or 2) |
padding |
int |
Zero-padding (use kh // 2 to preserve spatial size) |
Output shape: [out_ch, (H + 2*pad - kh) / stride + 1, (W + 2*pad - kw) / stride + 1]
add_conv2d_with_requant(kernel, bias, in_ch, out_ch, kh, kw, stride, padding, requant_m, requant_shift) โ Conv2D with Calibrated Requantization
Same as add_conv2d but with calibrated requantization for accuracy.
model.add_conv2d_with_requant(
kernel=[...], bias=[...],
in_ch=1, out_ch=8, kh=3, kw=3, stride=1, padding=1,
requant_m=2048, requant_shift=14
)
add_trainable_dense(in_features, out_features) โ Trainable Layer (RAM)
Weights live in RAM (for on-device fine-tuning). Not for frozen inference.
model.add_trainable_dense(128, 10) # 128 โ 10, weights in RAM
| Parameter | Type | Description |
|---|---|---|
in_features |
int |
Input dimension |
out_features |
int |
Output dimension |
RAM cost:
in_features ร out_features + out_featuresbytes
Activation Layers
| Method | Formula | When to use |
|---|---|---|
add_relu() |
max(0, x) |
Default choice, fastest |
add_sigmoid() |
1 / (1 + e^(-x/16)) |
Binary classification, fixed-scale |
add_sigmoid_scaled(mult, shift) |
Calibrated sigmoid LUT | After calibration |
add_tanh() |
tanh(x/32) |
Centered output [-1, 1], fixed-scale |
add_tanh_scaled(mult, shift) |
Calibrated tanh LUT | After calibration |
add_softmax() |
Pseudo-softmax approximation | Multi-class output (last layer) |
# Simple (no calibration needed)
model.add_relu()
# Calibrated (from calibrate_model output)
model.add_sigmoid_scaled(scale_mult=42, scale_shift=8)
model.add_tanh_scaled(scale_mult=84, scale_shift=8)
Important:
add_sigmoid()andadd_tanh()use a fixed scale divisor (16 and 32 respectively). For best accuracy, use the_scaledvariants with parameters fromcalibrate_model().
Structural Layers
| Method | Parameters | Description |
|---|---|---|
add_flatten() |
โ | Reshape 3D [C,H,W] โ 1D [CรHรW]. Use between conv and dense. |
add_max_pool2d(kernel, stride, padding) |
int, int, int |
Reduce spatial dims by taking max over kernel window |
model.add_max_pool2d(kernel=2, stride=2, padding=0)
# Input [8, 28, 28] โ Output [8, 14, 14]
Inference Methods
model.forward(input_data) โ List[int]
Run forward pass, get raw i8 output vector.
output = model.forward([100, -50, 30, 70])
print(output) # โ [15, -8, 22] (raw i8 activations)
model.predict(input_data) โ int
Run forward pass, get argmax class index.
class_id = model.predict([100, -50, 30, 70])
print(class_id) # โ 2
๐ง Python Utilities โ nano_rust_py.utils
All utilities are bundled in the PyPI package โ no need to clone the repo.
from nano_rust_py.utils import (
quantize_to_i8,
quantize_weights,
calibrate_model,
compute_requant_params,
compute_activation_scale_params,
export_to_rust,
export_weights_bin,
)
Note:
numpyis installed as a dependency.torchis only needed if you usequantize_weights()orcalibrate_model()โ install withpip install nano-rust-py[train].
These utilities bridge PyTorch training and NANO-RUST inference.
quantize_to_i8(tensor, scale=127.0) โ (np.ndarray, float)
Quantize any float32 tensor to i8 using symmetric linear scaling.
import numpy as np
from nano_rust_py.utils import quantize_to_i8
float_data = np.array([0.5, -0.3, 1.0, -1.0], dtype=np.float32)
q_data, scale = quantize_to_i8(float_data)
print(q_data) # โ [ 64, -38, 127, -127]
print(scale) # โ 0.00787 (max_abs / 127)
# To dequantize: float_value โ i8_value ร scale
print(q_data[0] * scale) # โ 0.503 โ 0.5 โ
quantize_weights(model) โ Dict
Walk a PyTorch model and quantize all weight tensors.
import torch.nn as nn
from nano_rust_py.utils import quantize_weights
model = nn.Sequential(
nn.Linear(784, 128),
nn.ReLU(),
nn.Linear(128, 10),
)
q = quantize_weights(model)
# Returns: {
# '0': {
# 'type': 'Linear',
# 'weights': np.ndarray (i8, shape [128, 784]),
# 'bias': np.ndarray (i8, shape [128]),
# 'weight_scale': 0.00312,
# 'bias_scale': 0.00156,
# 'params': {'in_features': 784, 'out_features': 128}
# },
# '2': {
# 'type': 'Linear',
# 'weights': np.ndarray (i8, shape [10, 128]),
# ...
# }
# }
# Note: ReLU (layer '1') has no weights, so it is skipped.
calibrate_model(model, input_tensor, q_weights, input_scale) โ Dict
Run float model and compute per-layer requantization parameters.
from nano_rust_py.utils import calibrate_model, quantize_to_i8, quantize_weights
# 1. Quantize weights
q_weights = quantize_weights(model)
# 2. Prepare a representative input
sample_input = torch.randn(1, 784)
q_input, input_scale = quantize_to_i8(sample_input.numpy().flatten())
# 3. Calibrate
cal = calibrate_model(model, sample_input, q_weights, input_scale)
# Returns: {
# '0': (requant_m=1234, requant_shift=15, bias_corrected=[...]),
# '2': (requant_m=5678, requant_shift=14, bias_corrected=[...]),
# }
Why calibrate? Without calibration, the library uses a generic
shift = ceil(log2(k)) + 7which is approximate. Calibration computes the exact scale ratio between input, weights, and output โ raising accuracy from ~85% to 95-99%.
compute_requant_params(input_scale, weight_scale, output_scale) โ (int, int)
Compute TFLite-style fixed-point multiplier and shift.
from nano_rust_py.utils import compute_requant_params
M, shift = compute_requant_params(
input_scale=0.00787, # from quantize_to_i8(input)
weight_scale=0.00312, # from quantize_weights(model)
output_scale=0.00450 # from quantize_to_i8(expected_output)
)
print(M, shift) # โ (1407, 15)
# Meaning: output_i8 โ (accumulator ร 1407) >> 15
export_to_rust(model, model_name, input_shape) โ str
Generate complete Rust source code for the model weights and builder function.
from nano_rust_py.utils import export_to_rust
rust_code = export_to_rust(model, "digit_classifier", input_shape=[1, 28, 28])
with open("generated/digit_classifier.rs", "w") as f:
f.write(rust_code)
Output file contains:
// Auto-generated by nano_rust_utils
static LAYER_0_W: &[i8] = &[10, -5, 3, ...];
static LAYER_0_B: &[i8] = &[1, -1, ...];
pub fn build_digit_classifier() -> SequentialModel<'static> {
let mut model = SequentialModel::new();
model.add(Box::new(FrozenDense::new_with_requant(
LAYER_0_W, LAYER_0_B, 784, 128, 1234, 15
).unwrap()));
model.add(Box::new(ReLULayer));
// ...
model
}
export_weights_bin(q_weights, output_dir) โ List[Path]
Export quantized weights to binary files for include_bytes! in Rust.
from nano_rust_py.utils import export_weights_bin
paths = export_weights_bin(q_weights, "output/")
# Creates:
# output/0_w.bin (128 ร 784 = 100,352 bytes)
# output/0_b.bin (128 bytes)
# output/2_w.bin (10 ร 128 = 1,280 bytes)
# output/2_b.bin (10 bytes)
๐ Notebooks โ Learning Guide
Prerequisites
pip install nano-rust-py numpy torch torchvision ipykernel
Open notebooks in Jupyter/VS Code and select your venv kernel.
Validation Notebooks (notebooks/)
| # | Notebook | What You'll Learn |
|---|---|---|
| 01 | 01_pipeline_validation |
Full pipeline: ConvโReLUโFlattenโDense. Bit-exact comparison between float32 and i8. |
| 02 | 02_mlp_classification |
DenseโReLUโDense (MLP). Manual weight quantization and verification. |
| 03 | 03_deep_cnn |
Deep CNN with ConvโReLUโMaxPool stacking. Memory estimation for MCU. |
| 04 | 04_activation_functions |
Side-by-side comparison: ReLU vs Sigmoid vs Tanh. Fixed vs scaled modes. |
| 05 | 05_transfer_learning |
Frozen backbone (Flash) + trainable head (RAM). Hybrid memory pattern. |
Real-World Test Scripts (notebooks-for-test/)
Each script follows the full workflow:
Train (GPU) โ Quantize โ Calibrate โ Build NANO Model โ Verify Accuracy
| # | Script | Task | Training Data | Accuracy |
|---|---|---|---|---|
| 06 | run_06_mnist.py |
Digit classification | MNIST (28ร28) | ~97% |
| 07 | run_07_fashion.py |
Fashion item recognition | Fashion-MNIST (28ร28) | ~87% |
| 08 | run_08_sensor.py |
Industrial anomaly detection | Synthetic sensor data | ~98% |
| 09 | run_09_keyword_spotting.py |
Voice keyword detection | Synthetic MFCC features | ~79% |
| 10 | run_10_text_classifier.py |
Text sentiment analysis | Bag-of-words features | 100% |
Run any script:
python notebooks-for-test/run_06_mnist.py
๐๏ธ The Complete Workflow
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ STEP 1: Train in PyTorch (PC/GPU) โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โข Define nn.Sequential model โ
โ โข Train on dataset (MNIST, sensor data, audio, etc.) โ
โ โข Achieve desired float32 accuracy โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ STEP 2: Quantize & Calibrate (Python) โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โข quantize_weights(model) โ i8 weights + scales โ
โ โข calibrate_model() โ requant_m, requant_shift per layer โ
โ โข Memory shrinks 4ร (float32 โ int8) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ STEP 3: Build NANO Model & Verify (Python) โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โข Create PySequentialModel with i8 weights โ
โ โข Run same test inputs โ compare with PyTorch โ
โ โข Verify accuracy loss < 5% (typically < 2%) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ STEP 4: Export to Rust (Python) โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โข export_to_rust(model, "my_model") โ .rs file โ
โ โข Contains: static weight arrays + builder function โ
โ โข Or export_weights_bin() โ .bin files for include_bytes! โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ STEP 5: Deploy to MCU (Rust) โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โข include!("my_model.rs") in firmware โ
โ โข Allocate arena buffer (stack/static) โ
โ โข Read sensor โ quantize input โ inference โ action โ
โ โข See examples/esp32_deploy.rs โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
๐๏ธ Architecture
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Python (PyTorch + nano_rust_utils) โ โ Train & Quantize
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ PyO3 Binding (nano_rust_py) โ โ Bridge
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Rust Core (nano-rust-core) โ โ Inference Engine
โ โโโโโโโโโโ โโโโโโโโโโ โโโโโโโโโโโ โ
โ โ math.rsโ โlayers/ โ โarena.rs โ โ
โ โ matmul โ โdense โ โbump ptr โ โ
โ โ conv2d โ โconv โ โckpt/rst โ โ
โ โ relu โ โpool โ โโโโโโโโโโโ โ
โ โsigmoid โ โflatten โ โ
โ โ tanh โ โactivateโ โ
โ โโโโโโโโโโ โโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Memory Layout on MCU
FLASH (read-only) RAM (read-write)
โโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ
โ Frozen weights โ โ Arena Buffer โ
โ - Conv2D kernels โ โ โโโโโโโโโโโโโโโโ โ
โ - Dense weights โ โ โ Intermediate โ โ
โ - Bias arrays โ โ โ activations โ โ
โ (.rs static arrays) โ โ โโโโโโโโโโโโโโโโค โ
โ โ โ โ Trainable โ โ
โ Cost: N bytes โ โ โ head weights โ โ
โ RAM cost: 0 bytes โ โ โโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ
Memory Budget Rules
| Component | Formula | Example (MNIST MLP) |
|---|---|---|
| Frozen weights | ฮฃ(in ร out) per dense + ฮฃ(in_ch ร out_ch ร kh ร kw) per conv |
100KB Flash |
| Arena buffer | 2 ร max(layer_output_size) |
2 ร 784 = 1.6KB RAM |
| Bias arrays | ฮฃ(out_features) per layer |
138 bytes Flash |
| Trainable head (if any) | in ร out + out |
1.3KB RAM |
ESP32 budget: 4MB Flash, 520KB RAM. A typical model uses <100KB Flash + <20KB RAM.
๐ ESP32 Deployment
See the complete examples:
examples/esp32_deploy.rsโ Rust firmware templateexamples/export_for_esp32.pyโ Python export pipeline
Quick Summary
# Python: export model
from nano_rust_utils import quantize_weights, calibrate_model, export_to_rust
rust_code = export_to_rust(trained_model, "my_model", input_shape=[416])
with open("src/model.rs", "w") as f:
f.write(rust_code)
// Rust firmware: use exported model
#![no_std]
include!("model.rs");
let mut arena_buf = [0u8; 16384];
let mut arena = Arena::new(&mut arena_buf);
let model = build_my_model();
let (output, _) = model.forward(&input_i8, &[416], &mut arena).unwrap();
let class = nano_rust_core::math::argmax_i8(output);
๐ง Rust Core API (for Firmware Developers)
Layers
use nano_rust_core::layers::*;
// Frozen layers (weights in Flash โ 0 bytes RAM)
let dense = FrozenDense::new_with_requant(weights, bias, 784, 128, 1234, 15)?;
let conv = FrozenConv2D::new_with_requant(kernel, bias, 1, 8, 3, 3, 1, 1, 2048, 14)?;
// Trainable layer (weights in RAM โ for fine-tuning)
let head = TrainableDense::new(128, 10);
// Activations
let _ = ReLULayer;
let _ = ScaledSigmoidLayer { scale_mult: 42, scale_shift: 8 };
let _ = ScaledTanhLayer { scale_mult: 84, scale_shift: 8 };
let _ = SoftmaxLayer;
// Structural
let _ = FlattenLayer;
let pool = MaxPool2DLayer::new(2, 2, 0)?;
Arena Allocator
use nano_rust_core::Arena;
let mut buf = [0u8; 32768];
let mut arena = Arena::new(&mut buf);
// Checkpoint/restore for scratch memory reuse
let cp = arena.checkpoint();
let scratch = arena.alloc_i8_slice(1024)?;
arena.restore(cp); // reclaim scratch memory
Sequential Model
use nano_rust_core::model::SequentialModel;
let mut model = SequentialModel::new();
model.add(Box::new(dense));
model.add(Box::new(ReLULayer));
model.add(Box::new(dense2));
let (output, out_shape) = model.forward(input, &[784], &mut arena)?;
let class = nano_rust_core::math::argmax_i8(output);
๐๏ธ Project Structure
nano-rust/
โโโ core/ # Rust no_std core library
โ โโโ src/
โ โโโ lib.rs # Crate root & re-exports
โ โโโ arena.rs # Bump pointer allocator
โ โโโ math.rs # Quantized matmul, conv2d, activations
โ โโโ error.rs # NanoError, NanoResult
โ โโโ model.rs # SequentialModel (layer pipeline)
โ โโโ layers/
โ โโโ mod.rs # Layer trait + Shape struct
โ โโโ dense.rs # FrozenDense + TrainableDense
โ โโโ conv.rs # FrozenConv2D (im2col+matmul)
โ โโโ activations.rs # ReLU, Sigmoid, Tanh, Softmax (LUT)
โ โโโ flatten.rs # Flatten 3Dโ1D
โ โโโ pooling.rs # MaxPool2D
โโโ py_binding/ # PyO3 Python bindings (compiled Rust)
โ โโโ src/lib.rs # PySequentialModel wrapper
โโโ python/ # Pure Python modules (bundled in PyPI)
โ โโโ nano_rust_py/
โ โโโ __init__.py # Package init โ re-exports Rust types
โ โโโ utils.py # Quantization, calibration, export tools
โโโ scripts/ # Standalone scripts (not in PyPI)
โ โโโ nano_rust_utils.py # Legacy utils (now in nano_rust_py.utils)
โ โโโ export.py # CLI weight exporter
โโโ notebooks/ # Validation notebooks (01-05)
โโโ notebooks-for-test/ # Real-world test scripts (06-10)
โโโ examples/ # ESP32 deployment examples
โโโ generated/ # Exported Rust weight files
โโโ pyproject.toml # pip/maturin build config
โโโ Cargo.toml # Rust workspace config
โโโ LICENSE # MIT
โโโ README.md
๐ ๏ธ Development Setup
Only needed if you want to modify the Rust source code:
# 1. Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# or: winget install Rustlang.Rust.MSVC
# 2. Clone and setup
git clone https://github.com/LeeNim/nano-rust.git
cd nano-rust
python -m venv .venv
source .venv/bin/activate # Linux/Mac
# .venv\Scripts\activate # Windows
# 3. Install deps
pip install maturin numpy torch torchvision ipykernel
# 4. Build from source
# Windows: set CARGO_TARGET_DIR outside OneDrive!
$env:CARGO_TARGET_DIR = "$env:USERPROFILE\.nanorust_target"
maturin develop --release
# 5. Verify
python -c "import nano_rust_py; print('OK')"
๐ License
MIT ยฉ 2026 Niem Le
๐ฎ Roadmap
- v0.1.0: Core inference engine with scale-aware requantization
- v0.2.0: Bundled Python utilities (
nano_rust_py.utils) in PyPI package - v0.3.0: Const Generics refactor for compile-time optimization
- v0.4.0: On-device training (backprop for trainable head)
- v0.5.0: ARM SIMD intrinsics (SMLAD) for Cortex-M
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nano_rust_py-0.2.0.tar.gz.
File metadata
- Download URL: nano_rust_py-0.2.0.tar.gz
- Upload date:
- Size: 46.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
966c9eabebafb8095994f9eb26b9cfb497900c43db483a66c86e1c3539a7b000
|
|
| MD5 |
285ec7c8c0da6f4e8b160efb3b67fa62
|
|
| BLAKE2b-256 |
c544738287acf6f56f4458d68ae6f74c2afecec386af4a2e7885ff807b60fa7f
|
File details
Details for the file nano_rust_py-0.2.0-cp39-cp39-win_amd64.whl.
File metadata
- Download URL: nano_rust_py-0.2.0-cp39-cp39-win_amd64.whl
- Upload date:
- Size: 167.6 kB
- Tags: CPython 3.9, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fab20839ad9301167bee22f9032a7fe0ef2caef78fd1c9282bc22d07779b6d13
|
|
| MD5 |
eb096e4383ecc8058cea55ca31799083
|
|
| BLAKE2b-256 |
fa93af23aa5933d4322eeeb246ab4e8fae090bf284b63ff1658ff0c542d1920b
|