babys first rust

This commit is contained in:
sneakers-the-rat 2024-03-14 01:11:15 -07:00
parent 22c08c7627
commit 84d1049b7d
Signed by untrusted user who does not match committer: jonny
GPG key ID: 6DCB96EF1E4D232D
10 changed files with 3326 additions and 0 deletions

22
Cargo.toml Normal file
View file

@ -0,0 +1,22 @@
[package]
name = "sryaml"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
pyo3 = { version = "0.20.3", features = ["extension-module", "serde"] }
serde = { version = "1.0.197", features = ["derive"] }
serde_yaml = "0.9.32"
[profile.release-lto]
inherits = "release"
lto = true
[lib]
# See https://github.com/PyO3/pyo3 for details
name = "_sryamllib" # private module to be nested into Python package
crate-type = ["cdylib"]
path = "src/rust/lib.rs"

2
MANIFEST.in Normal file
View file

@ -0,0 +1,2 @@
include Cargo.toml
recursive-include src/rust *.rs

View file

@ -1,2 +1,10 @@
# serde-yaml-python
## Resources
Stuff i gone and learned from
- https://rust.code-maven.com/read-arbitrary-yaml
- https://stackoverflow.com/questions/70193869/exporting-hashmap-of-hashmap-to-python

1
build-wheels.sh Executable file
View file

@ -0,0 +1 @@
ARCHFLAGS="-arch x86_64 -arch arm64" python -m build

17
pyproject.toml Normal file
View file

@ -0,0 +1,17 @@
[build-system]
requires = ["setuptools", "setuptools-rust"]
build-backend = "setuptools.build_meta"
[project]
name = "sryaml"
version = "0.1.0"
[tool.setuptools.packages]
find = { where= ["src"]}
[[tool.setuptools-rust.ext-modules]]
target = "sryaml._sryamllib"
binding = "PyO3" # Default value, can be omitted
[bdist_wheel]
py_limited_api= "cp38" # replace with desired minimum Python version

68
src/rust/lib.rs Normal file
View file

@ -0,0 +1,68 @@
use pyo3::prelude::*;
use std::collections::HashMap;
fn to_python(v: &serde_yaml::Value, py: Python<'_> ) -> PyObject {
match v {
serde_yaml::Value::Null => py.None(),
serde_yaml::Value::Bool(s) => s.to_object(py),
serde_yaml::Value::Number(s) => {
let oi64 = s.as_i64().map( |i| i.to_object( py ) );
let ou64 = s.as_u64().map( |i| i.to_object( py ) );
let of64 = s.as_f64().map( |i| i.to_object( py ) );
oi64.or( ou64 ).or( of64 ).expect( "number too large" )
},
serde_yaml::Value::String(s) => s.to_object(py),
serde_yaml::Value::Sequence(s) => {
let inner: Vec<_> = s.iter().map(|x| to_python(x, py)).collect();
inner.to_object( py )
}
serde_yaml::Value::Mapping(s) => {
// FIXME: This required a hack of casting the key to a string, idk what i'm doing here lmao
let inner : HashMap<_, _>= s.into_iter()
.map( |( k, v )| ( k.as_str(), to_python( v, py ) ) ).collect();
inner.to_object(py)
},
serde_yaml::Value::Tagged(_s) => todo!(),
}
}
#[repr(transparent)]
#[derive( Clone, Debug )]
struct ParsedValue( serde_yaml::Value );
impl ToPyObject for ParsedValue {
fn to_object( &self, py: Python<'_> ) -> PyObject {
to_python( &self.0, py )
}
}
#[pyfunction]
fn loads(text: &str) -> PyResult<String>{
Ok(text.to_string())
}
#[pyfunction]
fn load(path: &str, py: Python) -> PyResult<Py<PyAny>>{
let parsed: serde_yaml::Value = match std::fs::File::open(path) {
Ok(file) => match serde_yaml::from_reader(file) {
Ok(data) => data,
Err(err) => {
eprintln!("There was an error parsing the YAML file {}", err);
std::process::exit(1);
}
},
Err(error) => {
eprintln!("Error opening file {}: {}", path, error);
std::process::exit(1)
}
};
Ok(to_python(&parsed, py))
}
#[pymodule]
fn _sryamllib(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(loads, m)?)?;
m.add_function(wrap_pyfunction!(load, m)?)?;
Ok(())
}

1
src/sryaml/__init__.py Normal file
View file

@ -0,0 +1 @@
from ._sryamllib import loads, load

2
tests/data/basic.yaml Normal file
View file

@ -0,0 +1,2 @@
mydict:
what

3195
tests/data/meta.yaml Normal file

File diff suppressed because it is too large Load diff

10
tests/test_time.py Normal file
View file

@ -0,0 +1,10 @@
import timeit
from yaml import (load as yload, Loader)
import sryaml
metamodel = 'data/meta.yaml'
pyyaml_time = timeit.timeit("yload(metamodel, Loader=Loader)", globals=globals(), number=1000)
sryaml_time = timeit.timeit("sryaml.load(metamodel)", globals=globals(), number=1000)
print(f"pyyaml time: {pyyaml_time}")
print(f"sryaml time: {sryaml_time}")