commit 00e6a334973e2975488bb449e45cc3fd5ceb7b08
Author: Andy Pack <andy@sarsoo.xyz>
Date:   Thu Feb 13 18:05:31 2025 +0000

    initial commit

diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml
new file mode 100644
index 0000000..56b86e6
--- /dev/null
+++ b/.gitea/workflows/build.yml
@@ -0,0 +1,31 @@
+name: Build Binaries
+
+on:
+  # Runs on pushes targeting the default branch
+  push:
+
+jobs:
+  # Build job
+  build:
+    name: Build & Test
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v4
+        with:
+          github-server-url: https://gitea.sheep-ghoul.ts.net
+
+      - name: Install Rust
+        uses: actions-rs/toolchain@v1
+        with:
+          toolchain: stable
+
+      - name: Cargo Build
+        uses: actions-rs/cargo@v1
+        with:
+          command: build
+
+      - name: Cargo Test
+        uses: actions-rs/cargo@v1
+        with:
+          command: test
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..8f4cea8
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,88 @@
+name: Build Binaries
+
+on:
+  # Runs on pushes targeting the default branch
+  push:
+
+# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
+permissions:
+  contents: read
+  pages: write
+  id-token: write
+
+# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
+# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
+concurrency:
+  group: "pages"
+  cancel-in-progress: false
+
+jobs:
+  # Build job
+  build:
+    name: Build & Test
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+
+      - name: Install Rust
+        uses: actions-rs/toolchain@v1
+        with:
+          toolchain: stable
+
+      - name: Cargo Build
+        uses: actions-rs/cargo@v1
+        with:
+          command: build
+
+      - name: Cargo Test
+        uses: actions-rs/cargo@v1
+        with:
+          command: test
+
+  doc:
+    name: Build Documentation
+    environment:
+      name: github-pages
+      url: ${{ steps.deployment.outputs.page_url }}
+    runs-on: ubuntu-latest
+    needs: [ build ] # for ignoring bad builds
+    if: github.event_name == 'push' && github.ref == 'refs/heads/master'
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v4
+
+      - name: Setup Pages
+        uses: actions/configure-pages@v4
+
+      - name: Install Rust
+        uses: actions-rs/toolchain@v1
+        with:
+          toolchain: stable
+
+      - name: Build Docs
+        run: cargo doc --no-deps --document-private-items
+
+      - name: Add redirect
+        run: echo '<meta http-equiv="refresh" content="0;url=finlib/index.html">' > target/doc/index.html
+
+      - name: Remove lock file
+        run: rm target/doc/.lock
+
+      - name: Upload artifact
+        uses: actions/upload-pages-artifact@v3
+        with:
+          # Upload entire repository
+          path: './target/doc'
+
+  deploy:
+    name: Deploy Documentation
+    environment:
+      name: github-pages
+      url: ${{ steps.deployment.outputs.page_url }}
+    runs-on: ubuntu-latest
+    needs: doc
+    steps:
+      - name: Deploy to GitHub Pages
+        id: deployment
+        uses: actions/deploy-pages@v4
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..710eac3
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+/target
+bin
+obj
+.venv
+.idea
+/finlib-wasm/pkg
+/FinLib.NET/FinLib.sln.DotSettings.user
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..3754019
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,850 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "anstream"
+version = "0.6.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
+dependencies = [
+ "anstyle",
+ "once_cell",
+ "windows-sys",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+
+[[package]]
+name = "bitflags"
+version = "2.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
+
+[[package]]
+name = "bumpalo"
+version = "3.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
+
+[[package]]
+name = "cbindgen"
+version = "0.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eadd868a2ce9ca38de7eeafdcec9c7065ef89b42b32f0839278d55f35c54d1ff"
+dependencies = [
+ "clap",
+ "heck 0.4.1",
+ "indexmap",
+ "log",
+ "proc-macro2",
+ "quote",
+ "serde",
+ "serde_json",
+ "syn",
+ "tempfile",
+ "toml",
+]
+
+[[package]]
+name = "cc"
+version = "1.2.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda"
+dependencies = [
+ "shlex",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "clap"
+version = "4.5.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8acebd8ad879283633b343856142139f2da2317c96b05b4dd6181c61e2480184"
+dependencies = [
+ "clap_builder",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.5.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6ba32cbda51c7e1dfd49acc1457ba1a7dec5b64fe360e828acb13ca8dc9c2f9"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
+
+[[package]]
+name = "console_error_panic_hook"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "csbindgen"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c26b9831049b947d154bba920e4124053def72447be6fb106a96f483874b482a"
+dependencies = [
+ "regex",
+ "syn",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "errno"
+version = "0.3.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
+dependencies = [
+ "libc",
+ "windows-sys",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
+
+[[package]]
+name = "finlib"
+version = "0.0.1"
+dependencies = [
+ "pyo3",
+]
+
+[[package]]
+name = "finlib-ffi"
+version = "0.0.1"
+dependencies = [
+ "cbindgen",
+ "csbindgen",
+ "finlib",
+]
+
+[[package]]
+name = "finlib-wasm"
+version = "0.0.1"
+dependencies = [
+ "console_error_panic_hook",
+ "finlib",
+ "wasm-bindgen",
+ "wasm-bindgen-test",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+ "windows-targets",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
+
+[[package]]
+name = "heck"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "indexmap"
+version = "2.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "indoc"
+version = "2.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+
+[[package]]
+name = "itoa"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
+
+[[package]]
+name = "js-sys"
+version = "0.3.77"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
+dependencies = [
+ "once_cell",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.169"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
+
+[[package]]
+name = "log"
+version = "0.4.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "memoffset"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "minicov"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b"
+dependencies = [
+ "cc",
+ "walkdir",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
+
+[[package]]
+name = "portable-atomic"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "pyfinlib"
+version = "0.0.1"
+dependencies = [
+ "finlib",
+ "pyo3",
+]
+
+[[package]]
+name = "pyo3"
+version = "0.23.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57fe09249128b3173d092de9523eaa75136bf7ba85e0d69eca241c7939c933cc"
+dependencies = [
+ "cfg-if",
+ "indoc",
+ "libc",
+ "memoffset",
+ "once_cell",
+ "portable-atomic",
+ "pyo3-build-config",
+ "pyo3-ffi",
+ "pyo3-macros",
+ "unindent",
+]
+
+[[package]]
+name = "pyo3-build-config"
+version = "0.23.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1cd3927b5a78757a0d71aa9dff669f903b1eb64b54142a9bd9f757f8fde65fd7"
+dependencies = [
+ "once_cell",
+ "target-lexicon",
+]
+
+[[package]]
+name = "pyo3-ffi"
+version = "0.23.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dab6bb2102bd8f991e7749f130a70d05dd557613e39ed2deeee8e9ca0c4d548d"
+dependencies = [
+ "libc",
+ "pyo3-build-config",
+]
+
+[[package]]
+name = "pyo3-macros"
+version = "0.23.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91871864b353fd5ffcb3f91f2f703a22a9797c91b9ab497b1acac7b07ae509c7"
+dependencies = [
+ "proc-macro2",
+ "pyo3-macros-backend",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "pyo3-macros-backend"
+version = "0.23.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43abc3b80bc20f3facd86cd3c60beed58c3e2aa26213f3cda368de39c60a27e4"
+dependencies = [
+ "heck 0.5.0",
+ "proc-macro2",
+ "pyo3-build-config",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "regex"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
+
+[[package]]
+name = "rustix"
+version = "0.38.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
+dependencies = [
+ "bitflags",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
+
+[[package]]
+name = "ryu"
+version = "1.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.217"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.217"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.138"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_spanned"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "syn"
+version = "2.0.98"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "target-lexicon"
+version = "0.12.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
+
+[[package]]
+name = "tempfile"
+version = "3.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91"
+dependencies = [
+ "cfg-if",
+ "fastrand",
+ "getrandom",
+ "once_cell",
+ "rustix",
+ "windows-sys",
+]
+
+[[package]]
+name = "toml"
+version = "0.8.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148"
+dependencies = [
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_edit",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.22.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
+dependencies = [
+ "indexmap",
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
+
+[[package]]
+name = "unindent"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
+[[package]]
+name = "walkdir"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
+name = "wasi"
+version = "0.13.3+wasi-0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
+dependencies = [
+ "wit-bindgen-rt",
+]
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "rustversion",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
+dependencies = [
+ "bumpalo",
+ "log",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.50"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "once_cell",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "wasm-bindgen-test"
+version = "0.3.50"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "66c8d5e33ca3b6d9fa3b4676d774c5778031d27a578c2b007f905acf816152c3"
+dependencies = [
+ "js-sys",
+ "minicov",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "wasm-bindgen-test-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-test-macro"
+version = "0.3.50"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17d5042cc5fa009658f9a7333ef24291b1291a25b6382dd68862a7f3b969f69b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "web-sys"
+version = "0.3.77"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "winapi-util"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "winnow"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59690dea168f2198d1a3b0cac23b8063efcd11012f10ae4698f284808c8ef603"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "wit-bindgen-rt"
+version = "0.33.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
+dependencies = [
+ "bitflags",
+]
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..9666c80
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,29 @@
+[workspace]
+resolver = "2"
+
+members = [
+    "finlib",
+    "finlib-ffi",
+    "finlib-wasm",
+    "pyfinlib"
+]
+
+default-members = [
+    "finlib",
+    "finlib-ffi"
+]
+
+[workspace.package]
+version = "0.0.1"
+authors = ["sarsoo <andy@sarsoo.xyz>"]
+edition = "2021"
+
+[workspace.dependencies.pyo3]
+version = "0.23.4"
+# "abi3-py38" tells pyo3 (and maturin) to build using the stable ABI with minimum Python version 3.8
+features = ["extension-module", "abi3-py38"]
+
+[profile.release]
+# Tell `rustc` to optimize for small code size.
+opt-level = "s"
+lto = true
\ No newline at end of file
diff --git a/FinLib.NET/FinLib.Test/Basic.cs b/FinLib.NET/FinLib.Test/Basic.cs
new file mode 100644
index 0000000..d23738c
--- /dev/null
+++ b/FinLib.NET/FinLib.Test/Basic.cs
@@ -0,0 +1,16 @@
+namespace FinLib.Test;
+using FluentAssertions;
+
+public class Tests
+{
+    [SetUp]
+    public void Setup()
+    {
+    }
+
+    [Test]
+    public void TestAdd()
+    {
+        FinLib.Add(10, 10).Should().Be(20);
+    }
+}
\ No newline at end of file
diff --git a/FinLib.NET/FinLib.Test/FinLib.Test.csproj b/FinLib.NET/FinLib.Test/FinLib.Test.csproj
new file mode 100644
index 0000000..710a575
--- /dev/null
+++ b/FinLib.NET/FinLib.Test/FinLib.Test.csproj
@@ -0,0 +1,28 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+    <PropertyGroup>
+        <TargetFramework>net9.0</TargetFramework>
+        <LangVersion>latest</LangVersion>
+        <ImplicitUsings>enable</ImplicitUsings>
+        <Nullable>enable</Nullable>
+        <IsPackable>false</IsPackable>
+    </PropertyGroup>
+
+    <ItemGroup>
+        <PackageReference Include="coverlet.collector" Version="6.0.2"/>
+        <PackageReference Include="FluentAssertions" Version="8.0.1" />
+        <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1"/>
+        <PackageReference Include="NUnit" Version="4.2.2"/>
+        <PackageReference Include="NUnit.Analyzers" Version="4.3.0"/>
+        <PackageReference Include="NUnit3TestAdapter" Version="4.6.0"/>
+    </ItemGroup>
+
+    <ItemGroup>
+        <Using Include="NUnit.Framework"/>
+    </ItemGroup>
+
+    <ItemGroup>
+      <ProjectReference Include="..\FinLib\FinLib.csproj" />
+    </ItemGroup>
+
+</Project>
diff --git a/FinLib.NET/FinLib.sln b/FinLib.NET/FinLib.sln
new file mode 100644
index 0000000..524b55e
--- /dev/null
+++ b/FinLib.NET/FinLib.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FinLib", "FinLib\FinLib.csproj", "{3202C5E1-CD3C-4B3C-AA5D-C3C81F06D418}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FinLib.Test", "FinLib.Test\FinLib.Test.csproj", "{148E024C-07D0-4DC0-A3E2-A146E709897B}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{3202C5E1-CD3C-4B3C-AA5D-C3C81F06D418}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{3202C5E1-CD3C-4B3C-AA5D-C3C81F06D418}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{3202C5E1-CD3C-4B3C-AA5D-C3C81F06D418}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{3202C5E1-CD3C-4B3C-AA5D-C3C81F06D418}.Release|Any CPU.Build.0 = Release|Any CPU
+		{148E024C-07D0-4DC0-A3E2-A146E709897B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{148E024C-07D0-4DC0-A3E2-A146E709897B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{148E024C-07D0-4DC0-A3E2-A146E709897B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{148E024C-07D0-4DC0-A3E2-A146E709897B}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/FinLib.NET/FinLib/FinLib.cs b/FinLib.NET/FinLib/FinLib.cs
new file mode 100644
index 0000000..de1a631
--- /dev/null
+++ b/FinLib.NET/FinLib/FinLib.cs
@@ -0,0 +1,9 @@
+namespace FinLib;
+
+public static class FinLib
+{
+    public static ulong Add(ulong a, ulong b)
+    {
+        return NativeMethods.add(a, b);
+    }
+}
\ No newline at end of file
diff --git a/FinLib.NET/FinLib/FinLib.csproj b/FinLib.NET/FinLib/FinLib.csproj
new file mode 100644
index 0000000..c7e30a4
--- /dev/null
+++ b/FinLib.NET/FinLib/FinLib.csproj
@@ -0,0 +1,33 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFrameworks>netstandard2.0</TargetFrameworks>
+    <LangVersion>latest</LangVersion>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+
+  <PropertyGroup>
+    <PackageId>FinLib.NET</PackageId>
+    <Version>0.0.1</Version>
+    <Authors>sarsoo</Authors>
+  </PropertyGroup>
+
+  <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
+    <Content Include="..\..\target\debug\libfinlib_ffi.dylib">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+
+  <ItemGroup Condition=" '$(Configuration)' == 'Release' ">
+    <Content Include="..\..\target\release\libfinlib_ffi.dylib">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="csbindgen" Version="1.9.3">
+      <PrivateAssets>all</PrivateAssets>
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+    </PackageReference>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/FinLib.NET/FinLib/NativeMethods.cs b/FinLib.NET/FinLib/NativeMethods.cs
new file mode 100644
index 0000000..038515a
--- /dev/null
+++ b/FinLib.NET/FinLib/NativeMethods.cs
@@ -0,0 +1,9 @@
+using GroupedNativeMethodsGenerator;
+
+namespace FinLib;
+
+[GroupedNativeMethods]
+internal static unsafe partial class NativeMethods
+{
+
+}
\ No newline at end of file
diff --git a/FinLib.NET/FinLib/NativeMethods.g.cs b/FinLib.NET/FinLib/NativeMethods.g.cs
new file mode 100644
index 0000000..6a5d1a4
--- /dev/null
+++ b/FinLib.NET/FinLib/NativeMethods.g.cs
@@ -0,0 +1,30 @@
+// <auto-generated>
+// This code is generated by csbindgen.
+// DON'T CHANGE THIS DIRECTLY.
+// </auto-generated>
+#pragma warning disable CS8500
+#pragma warning disable CS8981
+using System;
+using System.Runtime.InteropServices;
+
+
+namespace FinLib
+{
+    internal static unsafe partial class NativeMethods
+    {
+        const string __DllName = "libfinlib_ffi";
+
+
+
+        [DllImport(__DllName, EntryPoint = "add", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        internal static extern ulong add(ulong left, ulong right);
+
+        [DllImport(__DllName, EntryPoint = "interest_compound", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
+        internal static extern float interest_compound(float principal, float rate, float time, float n);
+
+
+    }
+
+
+
+}
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..b9eeacd
--- /dev/null
+++ b/README.md
@@ -0,0 +1,18 @@
+# finlib
+
+# FFI
+
+## Python
+
+```
+cd pyfinlib
+source .venv/bin/activate
+maturin develop
+```
+
+## WASM
+
+```
+cd finlib-wasm
+wasm-pack build
+```
\ No newline at end of file
diff --git a/finlib-cpp/finlib-native.h b/finlib-cpp/finlib-native.h
new file mode 100644
index 0000000..3f3c94b
--- /dev/null
+++ b/finlib-cpp/finlib-native.h
@@ -0,0 +1,26 @@
+#pragma once
+
+/* Generated with cbindgen:0.28.0 */
+
+/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */
+
+#include <cstdarg>
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <ostream>
+#include <new>
+
+
+namespace finlib {
+
+
+extern "C" {
+
+uint64_t add(uint64_t left, uint64_t right);
+
+float interest_compound(float principal, float rate, float time, float n);
+
+}  // extern "C"
+
+}  // namespace finlib
diff --git a/finlib-ffi/Cargo.toml b/finlib-ffi/Cargo.toml
new file mode 100644
index 0000000..a9dbd41
--- /dev/null
+++ b/finlib-ffi/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "finlib-ffi"
+version.workspace = true
+authors.workspace = true
+edition.workspace = true
+
+[lib]
+crate-type = ["cdylib"]
+
+[dependencies]
+finlib = { path = "../finlib" }
+
+[build-dependencies]
+cbindgen = "0.28.0"
+csbindgen = "1.8.0"
\ No newline at end of file
diff --git a/finlib-ffi/build.rs b/finlib-ffi/build.rs
new file mode 100644
index 0000000..949bf2d
--- /dev/null
+++ b/finlib-ffi/build.rs
@@ -0,0 +1,26 @@
+extern crate cbindgen;
+extern crate csbindgen;
+
+use std::env;
+use cbindgen::Config;
+
+fn main() {
+    let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
+
+    let config = Config::from_file("./cbindgen.toml").unwrap();
+
+    cbindgen::Builder::new()
+        .with_crate(crate_dir)
+        .with_config(config)
+        .generate()
+        .expect("Unable to generate bindings")
+        .write_to_file("../finlib-cpp/finlib-native.h");
+
+    csbindgen::Builder::default()
+        .input_extern_file("src/lib.rs")
+        .input_extern_file("../finlib/src/lib.rs")
+        .csharp_dll_name("libfinlib_ffi")
+        .csharp_namespace("FinLib")
+        .generate_csharp_file("../FinLib.NET/FinLib/NativeMethods.g.cs")
+        .unwrap();
+}
\ No newline at end of file
diff --git a/finlib-ffi/cbindgen.toml b/finlib-ffi/cbindgen.toml
new file mode 100644
index 0000000..cd8eb52
--- /dev/null
+++ b/finlib-ffi/cbindgen.toml
@@ -0,0 +1,159 @@
+# This is a template cbindgen.toml file with all of the default values.
+# Some values are commented out because their absence is the real default.
+#
+# See https://github.com/mozilla/cbindgen/blob/master/docs.md#cbindgentoml
+# for detailed documentation of every option here.
+
+
+
+language = "C++"
+
+
+
+############## Options for Wrapping the Contents of the Header #################
+
+# header = "/* Text to put at the beginning of the generated file. Probably a license. */"
+# trailer = "/* Text to put at the end of the generated file */"
+# include_guard = "my_bindings_h"
+pragma_once = true
+autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */"
+include_version = true
+namespace = "finlib"
+#namespaces = []
+using_namespaces = []
+sys_includes = []
+includes = []
+no_includes = false
+# cpp_compat = true
+after_includes = ""
+
+
+
+
+############################ Code Style Options ################################
+
+braces = "NextLine"
+line_length = 100
+tab_width = 2
+documentation = true
+documentation_style = "auto"
+documentation_length = "full"
+line_endings = "LF" # also "CR", "CRLF", "Native"
+
+
+
+
+############################# Codegen Options ##################################
+
+style = "both"
+sort_by = "Name" # default for `fn.sort_by` and `const.sort_by`
+usize_is_size_t = true
+
+
+
+[defines]
+# "target_os = freebsd" = "DEFINE_FREEBSD"
+# "feature = serde" = "DEFINE_SERDE"
+
+
+
+[export]
+include = []
+exclude = []
+# prefix = "CAPI_"
+item_types = []
+renaming_overrides_prefixing = false
+
+
+
+[export.rename]
+
+
+
+[export.body]
+
+
+[export.mangle]
+
+
+[fn]
+rename_args = "None"
+# must_use = "MUST_USE_FUNC"
+# deprecated = "DEPRECATED_FUNC"
+# deprecated_with_note = "DEPRECATED_FUNC_WITH_NOTE"
+# no_return = "NO_RETURN"
+# prefix = "START_FUNC"
+# postfix = "END_FUNC"
+args = "auto"
+sort_by = "Name"
+
+
+
+
+[struct]
+rename_fields = "PascalCase"
+# must_use = "MUST_USE_STRUCT"
+# deprecated = "DEPRECATED_STRUCT"
+# deprecated_with_note = "DEPRECATED_STRUCT_WITH_NOTE"
+derive_constructor = false
+derive_eq = false
+derive_neq = false
+derive_lt = false
+derive_lte = false
+derive_gt = false
+derive_gte = false
+
+
+
+
+[enum]
+rename_variants = "None"
+# must_use = "MUST_USE_ENUM"
+# deprecated = "DEPRECATED_ENUM"
+# deprecated_with_note = "DEPRECATED_ENUM_WITH_NOTE"
+add_sentinel = false
+prefix_with_name = false
+derive_helper_methods = false
+derive_const_casts = false
+derive_mut_casts = false
+# cast_assert_name = "ASSERT"
+derive_tagged_enum_destructor = false
+derive_tagged_enum_copy_constructor = false
+enum_class = true
+private_default_tagged_enum_constructor = false
+
+
+
+
+[const]
+allow_static_const = true
+allow_constexpr = true
+sort_by = "Name"
+
+
+
+
+[macro_expansion]
+bitflags = false
+
+
+
+
+
+
+############## Options for How Your Rust library Should Be Parsed ##############
+
+[parse]
+parse_deps = false
+# include = []
+exclude = []
+clean = false
+extra_bindings = []
+
+
+
+[parse.expand]
+crates = []
+all_features = false
+default_features = true
+features = []
\ No newline at end of file
diff --git a/finlib-ffi/src/lib.rs b/finlib-ffi/src/lib.rs
new file mode 100644
index 0000000..3b11c1e
--- /dev/null
+++ b/finlib-ffi/src/lib.rs
@@ -0,0 +1,9 @@
+#[no_mangle]
+pub extern "C" fn add(left: u64, right: u64) -> u64 {
+    finlib::add(left, right)
+}
+
+#[no_mangle]
+pub extern "C" fn interest_compound(principal: f32, rate: f32, time: f32, n: f32) -> f32 {
+    finlib::interest::compound(principal, rate, time, n)
+}
\ No newline at end of file
diff --git a/finlib-wasm/Cargo.toml b/finlib-wasm/Cargo.toml
new file mode 100644
index 0000000..2b8b9ed
--- /dev/null
+++ b/finlib-wasm/Cargo.toml
@@ -0,0 +1,24 @@
+[package]
+name = "finlib-wasm"
+version.workspace = true
+authors.workspace = true
+edition.workspace = true
+
+[lib]
+crate-type = ["cdylib", "rlib"]
+
+[features]
+default = ["console_error_panic_hook"]
+
+[dependencies]
+wasm-bindgen = "0.2.100"
+finlib = { path = "../finlib" }
+
+# The `console_error_panic_hook` crate provides better debugging of panics by
+# logging them with `console.error`. This is great for development, but requires
+# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
+# code size when deploying.
+console_error_panic_hook = { version = "0.1.7", optional = true }
+
+[dev-dependencies]
+wasm-bindgen-test = "0.3.50"
\ No newline at end of file
diff --git a/finlib-wasm/js/index.js b/finlib-wasm/js/index.js
new file mode 100644
index 0000000..e69de29
diff --git a/finlib-wasm/js/package.json b/finlib-wasm/js/package.json
new file mode 100644
index 0000000..fbf570b
--- /dev/null
+++ b/finlib-wasm/js/package.json
@@ -0,0 +1,14 @@
+{
+  "name": "finlib",
+  "version": "1.0.0",
+  "main": "index.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "dependencies": {
+    "draught": "file:../pkg"
+  },
+  "author": "",
+  "license": "ISC",
+  "description": ""
+}
diff --git a/finlib-wasm/src/lib.rs b/finlib-wasm/src/lib.rs
new file mode 100644
index 0000000..985dde6
--- /dev/null
+++ b/finlib-wasm/src/lib.rs
@@ -0,0 +1,11 @@
+use wasm_bindgen::prelude::wasm_bindgen;
+
+#[wasm_bindgen]
+pub fn add(left: u64, right: u64) -> u64 {
+    finlib::add(left, right)
+}
+
+#[wasm_bindgen]
+pub fn compound(principal: f32, rate: f32, time: f32, n: f32) -> f32 {
+    finlib::interest::compound(principal, rate, time, n)
+}
\ No newline at end of file
diff --git a/finlib/Cargo.toml b/finlib/Cargo.toml
new file mode 100644
index 0000000..9fa3e1b
--- /dev/null
+++ b/finlib/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "finlib"
+version.workspace = true
+authors.workspace = true
+edition.workspace = true
+
+[dependencies]
+pyo3 = { workspace = true, optional = true }
+
+[features]
+py = ["dep:pyo3"]
\ No newline at end of file
diff --git a/finlib/src/interest/mod.rs b/finlib/src/interest/mod.rs
new file mode 100644
index 0000000..9aa3d87
--- /dev/null
+++ b/finlib/src/interest/mod.rs
@@ -0,0 +1,22 @@
+
+pub fn compound(principal: f32, rate: f32, time: f32, n: f32) -> f32 {
+    principal * f32::powf( 1f32 + (rate / n), time * n)
+}
+/// https://www.thecalculatorsite.com/finance/calculators/compoundinterestcalculator.php
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn annual_compound() {
+        let result = compound(100f32, 0.05f32, 1f32, 1f32);
+        assert_eq!(f32::round(result), 105f32);
+    }
+
+    #[test]
+    fn monthly_compound() {
+        let result = compound(100f32, 0.05f32, 1f32, 12f32);
+        assert_eq!(f32::round(result * 100f32) / 100f32, 105.12f32);
+    }
+}
diff --git a/finlib/src/lib.rs b/finlib/src/lib.rs
new file mode 100644
index 0000000..fb4057d
--- /dev/null
+++ b/finlib/src/lib.rs
@@ -0,0 +1,16 @@
+pub mod interest;
+
+pub fn add(left: u64, right: u64) -> u64 {
+    left + right
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn it_works() {
+        let result = add(2, 2);
+        assert_eq!(result, 4);
+    }
+}
diff --git a/pyfinlib/Cargo.toml b/pyfinlib/Cargo.toml
new file mode 100644
index 0000000..fad9f3e
--- /dev/null
+++ b/pyfinlib/Cargo.toml
@@ -0,0 +1,21 @@
+[package]
+name = "pyfinlib"
+version.workspace = true
+authors.workspace = true
+edition.workspace = true
+
+[lib]
+# The name of the native library. This is the name which will be used in Python to import the
+# library (i.e. `import string_sum`). If you change this, you must also change the name of the
+# `#[pymodule]` in `src/lib.rs`.
+name = "pyfinlib"
+# "cdylib" is necessary to produce a shared library for Python to import from.
+#
+# Downstream Rust code (including code in `bin/`, `examples/`, and `tests/`) will not be able
+# to `use string_sum;` unless the "rlib" or "lib" crate type is also included, e.g.:
+# crate-type = ["cdylib", "rlib"]
+crate-type = ["cdylib"]
+
+[dependencies]
+finlib = { path = "../finlib", features = ["py"] }
+pyo3 = { workspace = true }
\ No newline at end of file
diff --git a/pyfinlib/pyproject.toml b/pyfinlib/pyproject.toml
new file mode 100644
index 0000000..d0ddaa7
--- /dev/null
+++ b/pyfinlib/pyproject.toml
@@ -0,0 +1,7 @@
+[build-system]
+requires = ["maturin>=1.0,<2.0"]
+build-backend = "maturin"
+
+[tool.maturin]
+# "extension-module" tells pyo3 we want to build an extension module (skips linking against libpython.so)
+features = ["pyo3/extension-module"]
\ No newline at end of file
diff --git a/pyfinlib/requirements.txt b/pyfinlib/requirements.txt
new file mode 100644
index 0000000..c5c26ec
--- /dev/null
+++ b/pyfinlib/requirements.txt
@@ -0,0 +1 @@
+maturin==1.8.2
\ No newline at end of file
diff --git a/pyfinlib/src/lib.rs b/pyfinlib/src/lib.rs
new file mode 100644
index 0000000..883c922
--- /dev/null
+++ b/pyfinlib/src/lib.rs
@@ -0,0 +1,18 @@
+use pyo3::prelude::*;
+
+#[pyfunction]
+fn add(left: u64, right: u64) -> PyResult<u64> {
+    Ok(finlib::add(left, right))
+}
+
+#[pyfunction]
+pub fn compound(principal: f32, rate: f32, time: f32, n: f32) -> PyResult<f32> {
+    Ok(finlib::interest::compound(principal, rate, time, n))
+}
+
+#[pymodule]
+fn pyfinlib(m: &Bound<'_, PyModule>) -> PyResult<()> {
+    m.add_function(wrap_pyfunction!(add, m)?)?;
+    m.add_function(wrap_pyfunction!(compound, m)?)?;
+    Ok(())
+}
\ No newline at end of file