boxfnonce-0.1.1/.appveyor.yml010064400017500001750000000007511342526121200143620ustar0000000000000000environment: matrix: - APPVEYOR_RUST_CHANNEL: stable - APPVEYOR_RUST_CHANNEL: nightly install: # Install rust, x86_64-pc-windows-msvc host - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - rustup-init.exe -y --default-host x86_64-pc-windows-msvc --default-toolchain %APPVEYOR_RUST_CHANNEL% - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - rustc -vV - cargo -vV build_script: - cargo build --verbose test_script: - cargo test --verbose boxfnonce-0.1.1/.gitignore010064400017500001750000000000221342526121200136730ustar0000000000000000target Cargo.lock boxfnonce-0.1.1/.travis.yml010064400017500001750000000002271342526121200140230ustar0000000000000000language: rust rust: - stable - beta - nightly matrix: allow_failures: - rust: nightly after_success: - './.travis/travis-doc-upload.sh' boxfnonce-0.1.1/.travis/id_rsa.enc010064400017500001750000000062601342526121200152330ustar0000000000000000@%&Fo=07nBReZw}.*{TuʉZ}ө71UH?sʮA{;PNO} L3}ϕαv>y玩AG'\ G7(LKGiyY|"a:0D}_1K1K%?OQIPd:BJ.Efqǣ=j#U|k?ӫkQ*^zu!VCn&||ۉI&8w ngq!5gZ86,V LQ[-7Wnt('w 5jNxfd yQ*eStZ Z~Q?n]4X vWGeK'J~gSj q[R `/$ޯ]` Z$cehej)W U LMBDHCK! +S'#9Y(@B8 _J -4joKQlU8/,X.^q`iuTL< G^7R}[p'0DtkПϾilO* ӧn*o] @||ۖ-)ڌP4m]}sTN5<ʥϞ=N4 PK縄+wa3Yh*1˕-\0;F(9ijδ+id oĿ58FːR00O8\cP6э}a2Iҽ-&X͈CNN?vL/3Na* 1[-,Զ9In_NDN;ʚw w+#&GݫwO[78vw$K?|nɢ-*AL@9TF|31cx9S3ҺEV]Z'NyIJe m m*ԣa8OV'CCc[z#bB:^YK4W4BKF+_V`ovc ʥGÓJ 2zY4d> -[#/ut(hQ H|TqTۚ֎ a;|0ʐU'w`2fͮݶ ZW?i|#+J)8 ROj)U JnP)EFwP"`᷉O-ۤaq)fBS76x1k.UH&{)b8%'A^UM`>̜p c/rr`Q,)e+ɠFee^<^X?9/1 p0e\V'h,@!ЁdoLL~`{+62wG+4=X8|i{' I_Bq:a/CXpWT#M}ZƮtٵcE @#][}D,'8ZKzip:jg, >ٙNʻ)I7CKQ%LoLhMboxfnonce-0.1.1/.travis/travis-doc-upload.cfg010064400017500001750000000001231342526121200173110ustar0000000000000000PROJECT_NAME=boxfnonce DOCS_REPO=stbuehler/rustdocs SSH_KEY_TRAVIS_ID=68ecddba1483 boxfnonce-0.1.1/.travis/travis-doc-upload.sh010075500017500001750000000021771342526121200172020ustar0000000000000000#!/bin/sh # License: CC0 1.0 Universal # https://creativecommons.org/publicdomain/zero/1.0/legalcode set -e echo "Building docs..." cargo doc if [ "${TRAVIS_RUST_VERSION}" != "stable" ]; then echo "Only uploading docs for stable, not ${TRAVIS_RUST_VERSION}" exit 0 fi if [ "${TRAVIS_BRANCH}" != "master" ]; then echo "Only uploading docs for master branch, not ${TRAVIS_BRANCH}" exit 0 fi if [ "${TRAVIS_PULL_REQUEST}" != "false" ]; then echo "Not uploading docs for pull requests" exit 0 fi echo "Reading upload config..." . .travis/travis-doc-upload.cfg eval "key=\$encrypted_${SSH_KEY_TRAVIS_ID}_key" eval "iv=\$encrypted_${SSH_KEY_TRAVIS_ID}_iv" mkdir -p ~/.ssh openssl aes-256-cbc -K "${key}" -iv "${iv}" -in .travis/id_rsa.enc -out ~/.ssh/id_rsa -d chmod 600 ~/.ssh/id_rsa git clone --branch gh-pages "git@github.com:${DOCS_REPO}" deploy_docs cd deploy_docs git config user.name "doc upload bot" git config user.email "nobody@example.com" rm -rf "${PROJECT_NAME}" mv ../target/doc "${PROJECT_NAME}" git add -A "${PROJECT_NAME}" git commit -qm "doc upload for ${PROJECT_NAME} (${TRAVIS_REPO_SLUG})" git push -q origin gh-pages boxfnonce-0.1.1/Cargo.toml.orig010064400017500001750000000011201342527455200146050ustar0000000000000000[package] name = "boxfnonce" # also bump version in html_root_url in src/lib.rs version = "0.1.1" authors = ["Stefan Bühler "] description = "safe FnOnce boxing for rust stable" documentation = "https://stbuehler.github.io/rustdocs/boxfnonce/boxfnonce/" homepage = "https://github.com/stbuehler/rust-boxfnonce" repository = "https://github.com/stbuehler/rust-boxfnonce" readme = "README.md" keywords = ["Box", "FnOnce"] license = "MIT" [badges] travis-ci = { repository = "stbuehler/rust-boxfnonce" } appveyor = { repository = "stbuehler/rust-boxfnonce" } [dependencies] boxfnonce-0.1.1/Cargo.toml0000644000000020460000000000000110530ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g. crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "boxfnonce" version = "0.1.1" authors = ["Stefan Bühler "] description = "safe FnOnce boxing for rust stable" homepage = "https://github.com/stbuehler/rust-boxfnonce" documentation = "https://stbuehler.github.io/rustdocs/boxfnonce/boxfnonce/" readme = "README.md" keywords = ["Box", "FnOnce"] license = "MIT" repository = "https://github.com/stbuehler/rust-boxfnonce" [dependencies] [badges.appveyor] repository = "stbuehler/rust-boxfnonce" [badges.travis-ci] repository = "stbuehler/rust-boxfnonce" boxfnonce-0.1.1/LICENSE010064400017500001750000000020631342526121200127170ustar0000000000000000The MIT License Copyright (c) 2017 Stefan Bühler Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. boxfnonce-0.1.1/README.md010064400017500001750000000017441342526121200131760ustar0000000000000000[![Travis Build Status](https://travis-ci.org/stbuehler/rust-boxfnonce.svg?branch=master)](https://travis-ci.org/stbuehler/rust-boxfnonce) [![AppVeyor Status](https://ci.appveyor.com/api/projects/status/rilrs513t5p68b0d?svg=true)](https://ci.appveyor.com/project/stbuehler/rust-boxfnonce) [![crates.io](https://img.shields.io/crates/v/boxfnonce.svg)](https://crates.io/crates/boxfnonce) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) This library provide a safe way to box FnOnce types. It doesn't use any unstable features and is therefore fully compatible with rust stable. This library is provided because `Box` doesn't work yet, and `Box` will never be available in rust stable. The documentation for `master` is located at [https://stbuehler.github.io/rustdocs/boxfnonce/boxfnonce/](https://stbuehler.github.io/rustdocs/boxfnonce/boxfnonce/); released versions are documented at [https://docs.rs/boxfnonce](https://docs.rs/boxfnonce). boxfnonce-0.1.1/src/lib.rs010064400017500001750000000014331342527455700136350ustar0000000000000000#![warn(missing_docs)] #![doc(html_root_url = "https://docs.rs/boxfnonce/0.1.1")] //! See `BoxFnOnce` and `SendBoxFnOnce`. /* This crate requires: a) A trait can dispatch through `self: Box` too: The "object- safety" RFC[^1] lists the following arguments as "dispatchable": `self`, `&self`, `&mut self`, or `self: Box` b) If you have a v: Box for a concrete (`Sized`) type T, you can extract the boxed value with *t (seems undocumented). This basically duplicates what Box is doing, but without using any unstable interface. [1]: https://github.com/rust-lang/rfcs/blob/master/text/0255-object-safety.md#detailed-design */ #[macro_use] mod macros; mod traits; mod no_send; pub use self::no_send::BoxFnOnce; mod send; pub use self::send::SendBoxFnOnce; boxfnonce-0.1.1/src/macros.rs010064400017500001750000000016011342526121200143300ustar0000000000000000macro_rules! impl_trait_n_args { ( $($var:ident: $typevar:ident),* ) => ( impl<$($typevar,)* Result, F: FnOnce($($typevar),*) -> Result> FnBox<($($typevar,)*), Result> for F { fn call(self: Box, ($($var,)*): ($($typevar,)*)) -> Result { let this : Self = *self; this($($var),*) } } ) } macro_rules! build_n_args { ( $name:ident [$($add:tt)*]: $($var:ident: $typevar:ident),* ) => ( impl<'a, $($typevar,)* Result> $name<'a, ($($typevar,)*), Result> { /// call inner function, consumes the box. #[inline] pub fn call(self $(, $var: $typevar)*) -> Result { FnBox::call(self.0, ($($var ,)*)) } } impl<'a, $($typevar,)* Result, F: 'a + FnOnce($($typevar),*) -> Result $($add)*> From for $name<'a, ($($typevar,)*), Result> { fn from(func: F) -> Self { $name(Box::new(func) as Box $($add)* + 'a>) } } ) } boxfnonce-0.1.1/src/no_send.rs010064400017500001750000000111631342526152200145010ustar0000000000000000use traits::FnBox; /// `BoxFnOnce` boxes any `FnOnce` function up to a certain number of /// arguments (10 as of now). /// /// As `Box` doesn't work yet, and `Box` will not be /// available in stable rust, `BoxFnOnce` tries to provide a safe /// implementation. /// /// Instead of `Box Result + 'a>` (or /// `Box Result> + 'a`) the box type is `BoxFnOnce<'a, /// (Args...,), Result>` (the arguments are always given as tuple /// type). If the function doesn't return a value (i.e. the empty /// tuple) `Result` can be omitted: `BoxFnOnce<'a, (Args...,)>`. /// /// Internally it is implemented similar to `Box`, but there /// is no `FnOnce` implementation for `BoxFnOnce`. /// /// You can build boxes for diverging functions too, but specifying the /// type (like `BoxFnOnce<'a, (), !>`) is not possible as the `!` type /// is experimental. /// /// If you need to send the FnOnce use `SendBoxFnOnce` instead. /// /// # Examples /// /// Move value into closure and box it: /// /// ``` /// use boxfnonce::BoxFnOnce; /// let s = String::from("foo"); /// let f : BoxFnOnce<()> = BoxFnOnce::from(|| { /// println!("Got called: {}", s); /// drop(s); /// }); /// f.call(); /// ``` /// /// Move value into closure to return it, and box the closure: /// /// ``` /// use boxfnonce::BoxFnOnce; /// let s = String::from("foo"); /// let f : BoxFnOnce<(), String> = BoxFnOnce::from(|| { /// println!("Got called: {}", s); /// s /// }); /// assert_eq!(f.call(), "foo".to_string()); /// ``` pub struct BoxFnOnce<'a, Arguments, Result = ()> (Box + 'a>); impl<'a, Args, Result> BoxFnOnce<'a, Args, Result> { /// call inner function, consumes the box. /// /// `call_tuple` can be used if the arguments are available as /// tuple. Each usable instance of BoxFnOnce<(...), Result> has a /// separate `call` method for passing arguments "untupled". #[inline] pub fn call_tuple(self, args: Args) -> Result { self.0.call(args) } /// `BoxFnOnce::new` is an alias for `BoxFnOnce::from`. #[inline] pub fn new(func: F) -> Self where Self: From { Self::from(func) } } build_n_args!(BoxFnOnce[]: ); build_n_args!(BoxFnOnce[]: a1: A1); build_n_args!(BoxFnOnce[]: a1: A1, a2: A2); build_n_args!(BoxFnOnce[]: a1: A1, a2: A2, a3: A3); build_n_args!(BoxFnOnce[]: a1: A1, a2: A2, a3: A3, a4: A4); build_n_args!(BoxFnOnce[]: a1: A1, a2: A2, a3: A3, a4: A4, a5: A5); build_n_args!(BoxFnOnce[]: a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6); build_n_args!(BoxFnOnce[]: a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7); build_n_args!(BoxFnOnce[]: a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8); build_n_args!(BoxFnOnce[]: a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8, a9: A9); build_n_args!(BoxFnOnce[]: a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8, a9: A9, a10: A10); impl<'a, Arguments, Result> From> for BoxFnOnce<'a, Arguments, Result> { fn from(value: super::SendBoxFnOnce<'a, Arguments, Result>) -> Self { BoxFnOnce(value.0) } } #[cfg(test)] mod test { use super::BoxFnOnce; use std::rc::Rc; struct NoSendString(String, Rc<()>); impl NoSendString { fn into(self) -> String { self.0 } } fn closure_string() -> NoSendString { NoSendString(String::from("abc"), Rc::new(())) } #[test] fn test_arg0() { let f = BoxFnOnce::from({ let s = closure_string(); move || -> String { s.into() } }); assert_eq!(f.call(), "abc"); } #[test] fn test_arg1() { let f = BoxFnOnce::from({ let s = closure_string(); move |_| -> String { s.into() } }); assert_eq!(f.call(0), "abc"); } #[test] fn test_arg1_fixed_argument_type() { let f : BoxFnOnce<(i32,), String> = BoxFnOnce::from({ let s = closure_string(); move |_| -> String { s.into() } }); assert_eq!(f.call(0), "abc"); } #[test] fn test_arg2() { let f = BoxFnOnce::from({ let s = closure_string(); move |_, _| -> String { s.into() } }); assert_eq!(f.call(0, 0), "abc"); } #[test] fn test_arg3() { let f = BoxFnOnce::from({ let s = closure_string(); move |_, _, _| -> String { s.into() } }); assert_eq!(f.call(0, 0, 0), "abc"); } #[test] fn test_arg4_void() { let f = BoxFnOnce::from({ let s = closure_string(); move |_, _, _, _| { drop(s); } }); f.call(0, 0, 0, 0); } #[test] #[should_panic(expected = "inner diverging")] fn test_arg4_diverging() { let f = BoxFnOnce::from({ let s = closure_string(); move |_, _, _, _| -> ! { drop(s); panic!("inner diverging"); } }); f.call(0, 0, 0, 0); } } boxfnonce-0.1.1/src/send.rs010064400017500001750000000127361342526174700140250ustar0000000000000000use traits::FnBox; /// `SendBoxFnOnce` boxes any `FnOnce + Send` function up to a certain /// number of arguments (10 as of now). /// /// As `Box` doesn't work yet, and `Box` will not be /// available in stable rust, `SendBoxFnOnce` tries to provide a safe /// implementation. /// /// Instead of `Box Result + 'a>` (or /// `Box Result + 'a>`) the box type is /// `SendBoxFnOnce<'a, (Args...,), Result>` (the arguments are always given /// as tuple type). If the function doesn't return a value (i.e. the /// empty tuple) `Result` can be omitted: `SendBoxFnOnce<'a, (Args...,)>`. /// /// Internally it is implemented similar to `Box`, but there is /// no `FnOnce` implementation for `SendBoxFnOnce`. /// /// You can build boxes for diverging functions too, but specifying the /// type (like `SendBoxFnOnce<(), !>`) is not possible as the `!` type /// is experimental. /// /// # Examples /// /// Move value into closure to return it, box the closure and send it: /// /// ``` /// use boxfnonce::SendBoxFnOnce; /// use std::thread; /// /// let s = String::from("foo"); /// let f : SendBoxFnOnce<(), String> = SendBoxFnOnce::from(|| { /// println!("Got called: {}", s); /// s /// }); /// let result = thread::Builder::new().spawn(move || { /// f.call() /// }).unwrap().join().unwrap(); /// assert_eq!(result, "foo".to_string()); /// ``` pub struct SendBoxFnOnce<'a, Arguments, Result = ()> (pub(crate) Box + Send + 'a>); impl<'a, Args, Result> SendBoxFnOnce<'a, Args, Result> { /// call inner function, consumes the box. /// /// `call_tuple` can be used if the arguments are available as /// tuple. Each usable instance of SendBoxFnOnce<(...), Result> has /// a separate `call` method for passing arguments "untupled". #[inline] pub fn call_tuple(self, args: Args) -> Result { self.0.call(args) } /// `SendBoxFnOnce::new` is an alias for `SendBoxFnOnce::from`. #[inline] pub fn new(func: F) -> Self where Self: From { Self::from(func) } } build_n_args!(SendBoxFnOnce[+Send]: ); build_n_args!(SendBoxFnOnce[+Send]: a1: A1); build_n_args!(SendBoxFnOnce[+Send]: a1: A1, a2: A2); build_n_args!(SendBoxFnOnce[+Send]: a1: A1, a2: A2, a3: A3); build_n_args!(SendBoxFnOnce[+Send]: a1: A1, a2: A2, a3: A3, a4: A4); build_n_args!(SendBoxFnOnce[+Send]: a1: A1, a2: A2, a3: A3, a4: A4, a5: A5); build_n_args!(SendBoxFnOnce[+Send]: a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6); build_n_args!(SendBoxFnOnce[+Send]: a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7); build_n_args!(SendBoxFnOnce[+Send]: a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8); build_n_args!(SendBoxFnOnce[+Send]: a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8, a9: A9); build_n_args!(SendBoxFnOnce[+Send]: a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8, a9: A9, a10: A10); #[cfg(test)] mod test { use super::super::BoxFnOnce; use super::SendBoxFnOnce; use std::thread; use std::sync::Arc; struct SendString(String, Arc<()>); impl SendString { fn into(self) -> String { self.0 } } fn closure_string() -> SendString { SendString(String::from("abc"), Arc::new(())) } fn try_send(name: &str, func: F) -> thread::Result where Result: 'static + Send, F: 'static + Send + FnOnce() -> Result { thread::Builder::new().name(name.to_string()).spawn(func).unwrap().join() } fn send(func: F) -> Result where Result: 'static + Send, F: 'static + Send + FnOnce() -> Result { try_send("test thread", func).unwrap() } #[test] fn test_arg0() { let f = SendBoxFnOnce::from({ let s = closure_string(); || -> String { s.into() } }); let result = send(|| { f.call() }); assert_eq!(result, "abc"); } #[test] fn test_arg1() { let f = SendBoxFnOnce::from({ let s = closure_string(); |_| -> String { s.into() } }); let result = send(|| { f.call(0) }); assert_eq!(result, "abc"); } #[test] fn test_arg1_fixed_argument_type() { let f : SendBoxFnOnce<(i32,), String> = SendBoxFnOnce::from({ let s = closure_string(); |_| -> String { s.into() } }); let result = send(|| { f.call(0) }); assert_eq!(result, "abc"); } #[test] fn test_arg2() { let f = SendBoxFnOnce::from({ let s = closure_string(); |_, _| -> String { s.into() } }); let result = send(|| { f.call(0, 0) }); assert_eq!(result, "abc"); } #[test] fn test_arg3() { let f = SendBoxFnOnce::from({ let s = closure_string(); |_, _, _| -> String { s.into() } }); let result = send(|| { f.call(0, 0, 0) }); assert_eq!(result, "abc"); } #[test] fn test_arg4_void() { let f = SendBoxFnOnce::from({ let s = closure_string(); |_, _, _, _| { drop(s); } }); send(|| { f.call(0, 0, 0, 0); }); } #[test] fn test_arg4_diverging() { use std::panic; let f = SendBoxFnOnce::from({ let s = closure_string(); |_, _, _, _| -> ! { drop(s); // a panic! but without the default hook printing stuff panic::resume_unwind(Box::new("inner diverging")); } }); let result: Result<(), Box<&str>> = try_send("diverging test thread", || { f.call(0, 0, 0, 0); }).map_err(|e| e.downcast::<&str>().unwrap()); assert_eq!(result, Err(Box::new("inner diverging"))); } #[test] fn test_arg4_void_to_nosend() { let f = SendBoxFnOnce::from({ let s = closure_string(); |_, _, _, _| { drop(s); } }); let f = BoxFnOnce::from(f); f.call(0, 0, 0, 0); } } boxfnonce-0.1.1/src/traits.rs010064400017500001750000000014601342526121200143550ustar0000000000000000// basically duplicating the unstable `std::boxed::FnBox` pub trait FnBox { fn call(self: Box, args: Arguments) -> Result; } impl_trait_n_args!(); impl_trait_n_args!(a1: A1); impl_trait_n_args!(a1: A1, a2: A2); impl_trait_n_args!(a1: A1, a2: A2, a3: A3); impl_trait_n_args!(a1: A1, a2: A2, a3: A3, a4: A4); impl_trait_n_args!(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5); impl_trait_n_args!(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6); impl_trait_n_args!(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7); impl_trait_n_args!(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8); impl_trait_n_args!(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8, a9: A9); impl_trait_n_args!(a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8, a9: A9, a10: A10); boxfnonce-0.1.1/.cargo_vcs_info.json0000644000000001120000000000000130450ustar00{ "git": { "sha1": "58405ab1607636d35a0409a9ee511a014210360b" } }