{"id":24962066,"url":"https://github.com/rust-for-linux/pinned-init","last_synced_at":"2025-02-27T17:20:16.989Z","repository":{"id":57674231,"uuid":"482314498","full_name":"Rust-for-Linux/pinned-init","owner":"Rust-for-Linux","description":"Library facilitating safe pinned initialization","archived":false,"fork":false,"pushed_at":"2025-02-16T13:42:38.000Z","size":3040,"stargazers_count":33,"open_issues_count":2,"forks_count":8,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-02-20T16:09:02.780Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://crates.io/crates/pinned-init","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Rust-for-Linux.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-04-16T17:10:29.000Z","updated_at":"2025-02-16T13:42:36.000Z","dependencies_parsed_at":"2023-11-16T23:48:56.963Z","dependency_job_id":"20de4472-c865-42f5-8806-e4cb8b4e53d6","html_url":"https://github.com/Rust-for-Linux/pinned-init","commit_stats":null,"previous_names":["y86-dev/pinned-init"],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Rust-for-Linux%2Fpinned-init","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Rust-for-Linux%2Fpinned-init/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Rust-for-Linux%2Fpinned-init/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Rust-for-Linux%2Fpinned-init/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Rust-for-Linux","download_url":"https://codeload.github.com/Rust-for-Linux/pinned-init/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240840102,"owners_count":19866167,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-02-03T08:58:30.534Z","updated_at":"2025-02-27T17:20:16.968Z","avatar_url":"https://github.com/Rust-for-Linux.png","language":"Rust","readme":"[![Crates.io](https://img.shields.io/crates/v/pinned-init.svg)](https://crates.io/crates/pinned-init)\n[![Documentation](https://docs.rs/pinned-init/badge.svg)](https://docs.rs/pinned-init/)\n[![Dependency status](https://deps.rs/repo/github/Rust-for-Linux/pinned-init/status.svg)](https://deps.rs/repo/github/Rust-for-Linux/pinned-init)\n![License](https://img.shields.io/crates/l/pinned-init)\n[![Toolchain](https://img.shields.io/badge/toolchain-nightly-red)](#nightly-only)\n![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/Rust-for-Linux/pinned-init/test.yml)\n# Pinned-init\n\n\u003c!-- cargo-rdme start --\u003e\n\nLibrary to safely and fallibly initialize pinned `struct`s using in-place constructors.\n\n[Pinning][pinning] is Rust's way of ensuring data does not move.\n\nIt also allows in-place initialization of big `struct`s that would otherwise produce a stack\noverflow.\n\nThis library's main use-case is in [Rust-for-Linux]. Although this version can be used\nstandalone.\n\nThere are cases when you want to in-place initialize a struct. For example when it is very big\nand moving it from the stack is not an option, because it is bigger than the stack itself.\nAnother reason would be that you need the address of the object to initialize it. This stands\nin direct conflict with Rust's normal process of first initializing an object and then moving\nit into it's final memory location.\n\nThis library allows you to do in-place initialization safely.\n\n### Nightly Needed for `alloc` feature\n\nThis library requires the `allocator_api` unstable feature when the `alloc` feature\nis enabled and thus this feature can only be used with a nightly compiler.\nWhen enabling the `alloc` feature, the user will be required to activate\n`allocator_api` as well.\n\nThe feature is enabled by default, thus by default `pinned-init` will require a\nnightly compiler. However, using the crate on stable compilers is possible by\ndisabling `alloc`. In practice this will require the `std` feature, because\nstable compilers have neither `Box` nor `Arc` in no-std mode.\n\n## Overview\n\nTo initialize a `struct` with an in-place constructor you will need two things:\n- an in-place constructor,\n- a memory location that can hold your `struct` (this can be the [stack], an [`Arc\u003cT\u003e`],\n  [`Box\u003cT\u003e`] or any other smart pointer that implements [`InPlaceInit`]).\n\nTo get an in-place constructor there are generally three options:\n- directly creating an in-place constructor using the [`pin_init!`] macro,\n- a custom function/macro returning an in-place constructor provided by someone else,\n- using the unsafe function [`pin_init_from_closure()`] to manually create an initializer.\n\nAside from pinned initialization, this library also supports in-place construction without pinning,\nthe macros/types/functions are generally named like the pinned variants without the `pin`\nprefix.\n\n## Examples\n\nThrought some examples we will make use of the `CMutex` type which can be found in\n`../examples/mutex.rs`. It is essentially a rebuild of the `mutex` from the Linux kernel in userland. So\nit also uses a wait list and a basic spinlock. Importantly it needs to be pinned to be locked\nand thus is a prime candidate for using this library.\n\n### Using the [`pin_init!`] macro\n\nIf you want to use [`PinInit`], then you will have to annotate your `struct` with\n`#[`[`pin_data`]`]`. It is a macro that uses `#[pin]` as a marker for\n[structurally pinned fields]. After doing this, you can then create an in-place constructor via\n[`pin_init!`]. The syntax is almost the same as normal `struct` initializers. The difference is\nthat you need to write `\u003c-` instead of `:` for fields that you want to initialize in-place.\n\n```rust\nuse pinned_init::*;\n#[pin_data]\nstruct Foo {\n    #[pin]\n    a: CMutex\u003cusize\u003e,\n    b: u32,\n}\n\nlet foo = pin_init!(Foo {\n    a \u003c- CMutex::new(42),\n    b: 24,\n});\n```\n\n`foo` now is of the type [`impl PinInit\u003cFoo\u003e`]. We can now use any smart pointer that we like\n(or just the stack) to actually initialize a `Foo`:\n\n```rust\nlet foo: Result\u003cPin\u003cBox\u003cFoo\u003e\u003e, _\u003e = Box::pin_init(foo);\n```\n\nFor more information see the [`pin_init!`] macro.\n\n### Using a custom function/macro that returns an initializer\n\nMany types that use this library supply a function/macro that returns an initializer, because\nthe above method only works for types where you can access the fields.\n\n```rust\nlet mtx: Result\u003cPin\u003cArc\u003cCMutex\u003cusize\u003e\u003e\u003e, _\u003e = Arc::pin_init(CMutex::new(42));\n```\n\nTo declare an init macro/function you just return an [`impl PinInit\u003cT, E\u003e`]:\n\n```rust\n#[pin_data]\nstruct DriverData {\n    #[pin]\n    status: CMutex\u003ci32\u003e,\n    buffer: Box\u003c[u8; 1_000_000]\u003e,\n}\n\nimpl DriverData {\n    fn new() -\u003e impl PinInit\u003cSelf, Error\u003e {\n        try_pin_init!(Self {\n            status \u003c- CMutex::new(0),\n            buffer: Box::init(pinned_init::zeroed())?,\n        }? Error)\n    }\n}\n```\n\n### Manual creation of an initializer\n\nOften when working with primitives the previous approaches are not sufficient. That is where\n[`pin_init_from_closure()`] comes in. This `unsafe` function allows you to create a\n[`impl PinInit\u003cT, E\u003e`] directly from a closure. Of course you have to ensure that the closure\nactually does the initialization in the correct way. Here are the things to look out for\n(we are calling the parameter to the closure `slot`):\n- when the closure returns `Ok(())`, then it has completed the initialization successfully, so\n  `slot` now contains a valid bit pattern for the type `T`,\n- when the closure returns `Err(e)`, then the caller may deallocate the memory at `slot`, so\n  you need to take care to clean up anything if your initialization fails mid-way,\n- you may assume that `slot` will stay pinned even after the closure returns until `drop` of\n  `slot` gets called.\n\n```rust\nuse pinned_init::*;\nuse core::{ptr::addr_of_mut, marker::PhantomPinned, cell::UnsafeCell, pin::Pin};\nmod bindings {\n    extern \"C\" {\n        pub type foo;\n        pub fn init_foo(ptr: *mut foo);\n        pub fn destroy_foo(ptr: *mut foo);\n        #[must_use = \"you must check the error return code\"]\n        pub fn enable_foo(ptr: *mut foo, flags: u32) -\u003e i32;\n    }\n}\n\n/// # Invariants\n///\n/// `foo` is always initialized\n#[pin_data(PinnedDrop)]\npub struct RawFoo {\n    #[pin]\n    _p: PhantomPinned,\n    #[pin]\n    foo: UnsafeCell\u003cbindings::foo\u003e,\n}\n\nimpl RawFoo {\n    pub fn new(flags: u32) -\u003e impl PinInit\u003cSelf, i32\u003e {\n        // SAFETY:\n        // - when the closure returns `Ok(())`, then it has successfully initialized and\n        //   enabled `foo`,\n        // - when it returns `Err(e)`, then it has cleaned up before\n        unsafe {\n            pin_init_from_closure(move |slot: *mut Self| {\n                // `slot` contains uninit memory, avoid creating a reference.\n                let foo = addr_of_mut!((*slot).foo);\n\n                // Initialize the `foo`\n                bindings::init_foo(UnsafeCell::raw_get(foo));\n\n                // Try to enable it.\n                let err = bindings::enable_foo(UnsafeCell::raw_get(foo), flags);\n                if err != 0 {\n                    // Enabling has failed, first clean up the foo and then return the error.\n                    bindings::destroy_foo(UnsafeCell::raw_get(foo));\n                    Err(err)\n                } else {\n                    // All fields of `RawFoo` have been initialized, since `_p` is a ZST.\n                    Ok(())\n                }\n            })\n        }\n    }\n}\n\n#[pinned_drop]\nimpl PinnedDrop for RawFoo {\n    fn drop(self: Pin\u003c\u0026mut Self\u003e) {\n        // SAFETY: Since `foo` is initialized, destroying is safe.\n        unsafe { bindings::destroy_foo(self.foo.get()) };\n    }\n}\n```\n\nFor more information on how to use [`pin_init_from_closure()`], take a look at the uses inside\nthe `kernel` crate. The [`sync`] module is a good starting point.\n\n[`sync`]: https://github.com/Rust-for-Linux/linux/tree/rust-next/rust/kernel/sync\n[pinning]: https://doc.rust-lang.org/std/pin/index.html\n[structurally pinned fields]: https://doc.rust-lang.org/std/pin/index.html#pinning-is-structural-for-field\n[stack]: https://docs.rs/pinned-init/latest/pinned_init/macro.stack_pin_init.html\n[`Arc\u003cT\u003e`]: https://doc.rust-lang.org/stable/alloc/sync/struct.Arc.html\n[`Box\u003cT\u003e`]: https://doc.rust-lang.org/stable/alloc/boxed/struct.Box.html\n[`impl PinInit\u003cFoo\u003e`]: https://docs.rs/pinned-init/latest/pinned_init/trait.PinInit.html\n[`impl PinInit\u003cT, E\u003e`]: https://docs.rs/pinned-init/latest/pinned_init/trait.PinInit.html\n[`impl Init\u003cT, E\u003e`]: https://docs.rs/pinned-init/latest/pinned_init/trait.Init.html\n[Rust-for-Linux]: https://rust-for-linux.com/\n\n\u003c!-- cargo-rdme end --\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frust-for-linux%2Fpinned-init","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frust-for-linux%2Fpinned-init","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frust-for-linux%2Fpinned-init/lists"}