Skip to content

v0.5.1 #22

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
May 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@ jobs:
- uses: actions/checkout@v3
- name: Build
run: cargo build --verbose --all
# There are currently no tests for macos
#- name: Run tests
# run: cargo test --verbose -- --skip test_vk_instance_layer_properties
- name: Run tests
# Skipping vulkan test because drivers are not guarenteed to be on the system.
run: cargo test --verbose -- --skip test_vk_instance_layer_properties
5 changes: 1 addition & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "dylink"
version = "0.5.0"
version = "0.5.1"
authors = ["Jonathan Thomason"]
edition = "2021"
license = "MIT OR Apache-2.0"
Expand All @@ -12,9 +12,6 @@ publish = true
[workspace]
members = ["dylink_macro"]

[dependencies]
once_cell = "1.16"

[dependencies.dylink_macro]
version = "0.6"
path="./dylink_macro"
Expand Down
45 changes: 37 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Dylink

![Crates.io](https://img.shields.io/crates/l/dylink) ![Crates.io](https://img.shields.io/crates/v/dylink) ![Crates.io](https://img.shields.io/crates/d/dylink) ![docs.rs](https://img.shields.io/docsrs/dylink) ![unsafe:yes](https://img.shields.io/badge/unsafe-yes-red)
![Crates.io](https://img.shields.io/crates/l/dylink) ![Crates.io](https://img.shields.io/crates/v/dylink) ![Crates.io](https://img.shields.io/crates/d/dylink) ![docs.rs](https://img.shields.io/docsrs/dylink) [![dylink-rs](https://github.com/Razordor/dylink/actions/workflows/rust.yml/badge.svg)](https://github.com/Razordor/dylink/actions/workflows/rust.yml) ![unsafe:yes](https://img.shields.io/badge/unsafe-yes-red)

Dylink provides a run-time dynamic linking framework for lazily evaluating shared libraries such as `.dll` files for windows
and `.so` files for unix. When functions are loaded they are evaluated through a thunk for first time calls, which loads the
function from it's respective library. Proceeding calls after initialization have no overhead or additional branching checks,
Dylink provides a run-time dynamic linking framework for lazily evaluating shared libraries such as `.dll` files.
When functions are loaded they are evaluated through a thunk for first time calls, which loads the function from
it's respective library. Proceeding calls after initialization have no overhead or additional branching checks,
as the thunk is replaced by the loaded function.

----
Expand All @@ -16,11 +16,11 @@ Related links:

## Supported platforms

Dylink has been implemented for all major platforms aside from WASM, but has only been locally tested on Windows and Linux.
Dylink has been implemented for all major platforms.

| Win64 | Linux | MacOS | Unix(other) | WASM |
|:-----:|:-----:|:--------:|:-----------:|------|
| YES | YES | Untested | Untested | NO |
| Windows | Linux | MacOS | WASM |
|:-------:|:-----:|:-----:|------|
| YES | YES | YES | NO |

## Usage

Expand Down Expand Up @@ -53,6 +53,35 @@ fn main() {
}
```

## Adv. Example

The `dylink` macro is also sophisticated enough to survive in `impl` blocks, and take advantage of the receiver argument `self`.
Unfortunately, `Self` cannot be internally inferred, so `self` without an explicit type also cannot be inferred.
The example below demonstrates how to work around these issues despite that:

```rust
use dylink::dylink;

#[derive(Debug, PartialEq)]
#[repr(transparent)]
struct Foo(u32);

impl Foo {
#[dylink(name = "Kernel32.dll")]
extern "stdcall" fn GetLastError() -> Foo;
#[dylink(name = "Kernel32.dll")]
extern "stdcall" fn SetLastError(self: Foo);
}

fn main() {
let foo = Foo(43);
unsafe {
foo.SetLastError();
assert_eq!(Foo(43), Foo::GetLastError());
}
}
```

### License

Licensed under either of
Expand Down
2 changes: 1 addition & 1 deletion dylink_macro/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "dylink_macro"
version = "0.6.0"
version = "0.6.1"
authors = ["Jonathan Thomason"]
edition = "2021"
readme = "README.md"
Expand Down
57 changes: 39 additions & 18 deletions dylink_macro/src/attr_data.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// Copyright (c) 2023 Jonathan "Razordor" Alan Thomason
use proc_macro2::{Span as Span2, TokenStream as TokenStream2};
use proc_macro2::TokenStream as TokenStream2;
use std::str::FromStr;
use syn::punctuated::Punctuated;
use syn::{spanned::Spanned, *};

pub struct AttrData {
pub strip: Option<Span2>,
pub strip: bool,
pub link_ty: LinkType,
pub linker: Option<Ident>,
}

#[derive(PartialEq)]
Expand All @@ -19,8 +20,9 @@ pub enum LinkType {
impl TryFrom<Punctuated<Expr, Token!(,)>> for AttrData {
type Error = syn::Error;
fn try_from(value: Punctuated<Expr, Token!(,)>) -> Result<Self> {
let mut strip: Option<Span2> = None;
let mut maybe_strip: Option<bool> = None;
let mut maybe_link_ty: Option<LinkType> = None;
let mut linker: Option<Ident> = None;
let mut errors = vec![];
const EXPECTED_KW: &str = "Expected `vulkan`, `any`, `strip`, or `name`.";

Expand All @@ -38,11 +40,14 @@ impl TryFrom<Punctuated<Expr, Token!(,)>> for AttrData {
errors.push(Error::new(path.span(), EXPECTED_KW));
}
}
// Branch for syntax: #[dylink(name = "")]
Expr::Assign(assign) => {
let (assign_left, assign_right) = (assign.left.as_ref(), assign.right.as_ref());
if matches!(assign_left, Expr::Path(ExprPath { path, .. }) if path.is_ident("name"))
{

let Expr::Path(ExprPath { path, .. }) = assign_left else {
unreachable!("internal error when parsing Expr::Assign");
};
if path.is_ident("name") {
// Branch for syntax: #[dylink(name = <string literal>)]
match assign_right {
Expr::Lit(ExprLit {
lit: Lit::Str(lib), ..
Expand All @@ -60,28 +65,43 @@ impl TryFrom<Punctuated<Expr, Token!(,)>> for AttrData {
errors.push(Error::new(right.span(), "Expected string literal."))
}
}
} else if matches!(assign_left, Expr::Path(ExprPath { path, .. }) if path.is_ident("strip"))
{
} else if path.is_ident("strip") {
// Branch for syntax: #[dylink(strip = <bool>)]
match assign_right {
Expr::Lit(ExprLit {
lit: Lit::Bool(val),
..
}) => {
if val.value() {
if strip.is_none() {
strip = Some(val.span())
} else {
errors.push(Error::new(
assign.span(),
"strip is already defined",
));
}
if maybe_strip.is_none() {
maybe_strip = Some(val.value());
} else {
errors.push(Error::new(
assign.span(),
"strip is already defined",
));
}
}
right => {
errors.push(Error::new(right.span(), "Expected boolean literal."))
}
}
} else if path.is_ident("linker") {
// Branch for syntax: #[dylink(linker = <ident>)]
match assign_right {
Expr::Path(ExprPath { path, .. }) => {
if linker.is_none() {
linker = Some(path.get_ident().unwrap().clone());
} else {
errors.push(Error::new(
assign.span(),
"linker is already defined",
));
}
}
right => {
errors.push(Error::new(right.span(), "Expected identifier."))
}
}
} else {
errors.push(Error::new(assign_left.span(), EXPECTED_KW));
}
Expand Down Expand Up @@ -152,8 +172,9 @@ impl TryFrom<Punctuated<Expr, Token!(,)>> for AttrData {
}
} else {
Ok(Self {
strip,
strip: maybe_strip.unwrap_or_default(),
link_ty: maybe_link_ty.unwrap(),
linker,
})
}
}
Expand Down
Loading