Skip to content

Commit c612f2b

Browse files
author
Eduardo Contin
committed
Implement polymorphic function macro with deterministic selection; add README, LICENSE, and CI workflow. Update example project and dependencies.
1 parent e3822d1 commit c612f2b

File tree

11 files changed

+336
-219
lines changed

11 files changed

+336
-219
lines changed

.github/workflows/ci.yml

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
name: Rust CI
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
env:
10+
CARGO_TERM_COLOR: always
11+
12+
jobs:
13+
test:
14+
name: Test
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/checkout@v3
18+
- uses: dtolnay/rust-toolchain@stable
19+
- uses: Swatinem/rust-cache@v2
20+
- name: Run tests
21+
run: cargo test --verbose
22+
23+
clippy:
24+
name: Clippy
25+
runs-on: ubuntu-latest
26+
steps:
27+
- uses: actions/checkout@v3
28+
- uses: dtolnay/rust-toolchain@stable
29+
with:
30+
components: clippy
31+
- uses: Swatinem/rust-cache@v2
32+
- name: Clippy check
33+
run: cargo clippy -- -D warnings
34+
35+
formatting:
36+
name: Formatting
37+
runs-on: ubuntu-latest
38+
steps:
39+
- uses: actions/checkout@v3
40+
- uses: dtolnay/rust-toolchain@stable
41+
with:
42+
components: rustfmt
43+
- name: Check formatting
44+
run: cargo fmt --all -- --check
45+
46+
publish:
47+
name: Publish
48+
needs: [test, clippy, formatting]
49+
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
50+
runs-on: ubuntu-latest
51+
steps:
52+
- uses: actions/checkout@v3
53+
- uses: dtolnay/rust-toolchain@stable
54+
- uses: Swatinem/rust-cache@v2
55+
- name: Login to crates.io
56+
run: cargo login ${{ secrets.CRATES_IO_TOKEN }}
57+
- name: Publish
58+
run: |
59+
cd polymorphic_fn
60+
cargo publish

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
*/target
1+
*/target
2+
.cursor/rules/riper-5.mdc

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2023 Your Name
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# polymorphic_fn
2+
3+
[![Crates.io](https://img.shields.io/crates/v/polymorphic_fn.svg)](https://crates.io/crates/polymorphic_fn)
4+
[![Documentation](https://docs.rs/polymorphic_fn/badge.svg)](https://docs.rs/polymorphic_fn)
5+
[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
6+
7+
A Rust procedural macro that enables functions with multiple implementations, where one is deterministically selected at compile-time.
8+
9+
## Features
10+
11+
- Define multiple function implementations in a single macro call
12+
- One implementation is deterministically selected at compile-time
13+
- Unused implementations are entirely removed from the binary
14+
- Selection is based on function name, build timestamp, and other factors
15+
- Useful for A/B testing, feature comparison, and binary size optimization
16+
17+
## Installation
18+
19+
Add this to your `Cargo.toml`:
20+
21+
```toml
22+
[dependencies]
23+
polymorphic_fn = "0.1.0"
24+
```
25+
26+
## Usage
27+
28+
### Basic Example
29+
30+
```rust
31+
use polymorphic_fn::polymorphic_fn;
32+
33+
polymorphic_fn! {
34+
pub fn calculate(x: i32) -> i32 {
35+
{ x + 1 }, // Implementation 1
36+
{ x * 2 }, // Implementation 2
37+
{ x * x } // Implementation 3
38+
}
39+
}
40+
41+
fn main() {
42+
let result = calculate(5);
43+
println!("Result: {}", result); // Will print result from one of the implementations
44+
}
45+
```
46+
47+
### Use Cases
48+
49+
#### Binary Size Optimization
50+
51+
```rust
52+
use polymorphic_fn::polymorphic_fn;
53+
54+
// Define alternative implementations with different size characteristics
55+
fn small_implementation(data: &[u8]) -> u64 {
56+
// Simple, small implementation
57+
data.iter().map(|&b| b as u64).sum()
58+
}
59+
60+
fn large_implementation(data: &[u8]) -> u64 {
61+
// Complex implementation with more features but larger code size
62+
// (e.g., includes optimizations, debug code, etc.)
63+
static LARGE_DATA: [u8; 1_000_000] = [0; 1_000_000];
64+
data.iter().zip(LARGE_DATA.iter())
65+
.map(|(&a, &b)| (a as u64) * (b as u64 + 1))
66+
.sum()
67+
}
68+
69+
polymorphic_fn! {
70+
pub fn process_data(data: &[u8]) -> u64 {
71+
{ small_implementation(data) },
72+
{ large_implementation(data) }
73+
}
74+
}
75+
```
76+
77+
#### Implementation A/B Testing
78+
79+
```rust
80+
use polymorphic_fn::polymorphic_fn;
81+
82+
polymorphic_fn! {
83+
pub fn sort_algorithm<T: Ord + Copy>(data: &mut [T]) {
84+
{
85+
// Implementation 1: Quick sort
86+
data.sort_unstable();
87+
},
88+
{
89+
// Implementation 2: Insertion sort
90+
for i in 1..data.len() {
91+
let mut j = i;
92+
while j > 0 && data[j-1] > data[j] {
93+
data.swap(j-1, j);
94+
j -= 1;
95+
}
96+
}
97+
}
98+
}
99+
}
100+
```
101+
102+
## How It Works
103+
104+
The `polymorphic_fn` macro uses compile-time hashing to deterministically select one implementation from the provided alternatives. The selection is based on:
105+
106+
1. The function name
107+
2. Build timestamp
108+
3. Package name and version
109+
4. Target architecture and profile
110+
5. A build counter that increments on each build
111+
112+
This ensures that the selection is consistent for a given build but can change between builds, allowing for different implementations to be tested over time.
113+
114+
## Controlling Selection
115+
116+
To force a rebuild and potentially get a different implementation selected, you can:
117+
118+
1. Use a build script with `cargo:rerun-if-changed=nonexistent-file` to ensure the build script runs every time
119+
2. Set the `FORCE_REBUILD` environment variable before building
120+
3. Increment a build counter in your build script
121+
122+
## License
123+
124+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

example/Cargo.lock

Lines changed: 1 addition & 101 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

example/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
name = "example"
33
version = "0.1.0"
44
edition = "2021"
5+
build = "build.rs"
56

67
[dependencies]
78
polymorphic_fn = { path = "../polymorphic_fn" }

0 commit comments

Comments
 (0)