{"action":"created","comment":{"url":"https://api.github.com/repos/bsteinb/rsmpi/pulls/comments/118572250","pull_request_review_id":40369933,"id":118572250,"diff_hunk":"@@ -433,6 +450,201 @@ unsafe impl<T> BufferMut for T where T: Equivalence\n unsafe impl<T> BufferMut for [T] where T: Equivalence\n {}\n \n+/// An immutable dynamically-typed buffer.\n+///\n+/// The buffer has a definite length and MPI datatype, but it is not yet known which Rust type it\n+/// corresponds to.  This is like the MPI analogue of `&Any`.\n+#[derive(Copy, Clone, Debug)]\n+pub struct DynBuffer<'a> {\n+    ptr: *const c_void,\n+    len: Count,\n+    datatype: BorrowedDatatype<'a>,\n+}\n+\n+unsafe impl<'a> Collection for DynBuffer<'a> {\n+    fn count(&self) -> Count {\n+        self.len\n+    }\n+}\n+\n+unsafe impl<'a> Pointer for DynBuffer<'a> {\n+    unsafe fn pointer(&self) -> *const c_void {\n+        self.ptr\n+    }\n+}\n+\n+unsafe impl<'a> AsDatatype for DynBuffer<'a> {\n+    type Out = BorrowedDatatype<'a>;\n+    fn as_datatype(&self) -> Self::Out {\n+        self.datatype\n+    }\n+}\n+\n+unsafe impl<'a> Buffer for DynBuffer<'a> {}\n+\n+impl<'a> DynBuffer<'a> {\n+    /// Creates a buffer from a slice with whose type has an MPI equivalent.\n+    pub fn new<T: Equivalence>(buf: &'a [T]) -> Self {\n+        unsafe {\n+            let datatype = BorrowedDatatype::from_raw(\n+                T::equivalent_datatype().as_raw());\n+            Self::from_raw(buf.as_ptr(), buf.count(), datatype)\n+        }\n+    }\n+\n+    /// Tests whether the buffer type matches `T`.\n+    pub fn is<T: Equivalence>(&self) -> bool {\n+        self.as_datatype().as_raw() == T::equivalent_datatype().as_raw()\n+    }\n+\n+    /// Returns some slice if the type matches `T`, or `None` if it doesn't.\n+    pub fn downcast<T: Equivalence>(&self) -> Option<&[T]> {\n+        if self.is::<T>() {\n+            unsafe { Some(slice::from_raw_parts(self.as_ptr() as _, self.len())) }\n+        } else {\n+            None\n+        }\n+    }\n+\n+    /// Creates a buffer from its raw components.  The buffer must remain valid for `'a`.\n+    pub unsafe fn from_raw<T>(ptr: *const T,\n+                              len: Count,\n+                              datatype: BorrowedDatatype<'a>) -> Self {\n+        Self { ptr: ptr as _, len, datatype }\n+    }\n+\n+    /// Returns the number of elements in the buffer.\n+    pub fn len(&self) -> usize {\n+        self.count().value_as().expect(\"Length of DynBuffer cannot be expressed as a usize\")\n+    }\n+\n+    /// Returns the underlying raw pointer.\n+    pub fn as_ptr(&self) -> *const c_void {\n+        self.ptr\n+    }\n+\n+    /// Reborrow the buffer with a shorter lifetime.\n+    pub fn as_ref<'b>(self) -> DynBuffer<'b> where 'a: 'b {\n+        unsafe { DynBuffer::from_raw(self.as_ptr(),\n+                                     self.count(),\n+                                     self.as_datatype()) }\n+    }\n+}\n+\n+/// An mutable dynamically-typed buffer.\n+///\n+/// The buffer has a definite length and MPI datatype, but it is not yet known which Rust type it\n+/// corresponds to.  This is like the MPI analogue of `&mut Any`.\n+#[derive(Debug)]\n+pub struct DynBufferMut<'a> {\n+    ptr: *mut c_void,\n+    len: Count,\n+    datatype: BorrowedDatatype<'a>,\n+}\n+\n+unsafe impl<'a> Send for DynBufferMut<'a> {}\n+\n+unsafe impl<'a> Sync for DynBufferMut<'a> {}\n+\n+unsafe impl<'a> Collection for DynBufferMut<'a> {\n+    fn count(&self) -> Count {\n+        self.len\n+    }\n+}\n+\n+unsafe impl<'a> Pointer for DynBufferMut<'a> {\n+    unsafe fn pointer(&self) -> *const c_void {\n+        self.ptr\n+    }\n+}\n+\n+unsafe impl<'a> PointerMut for DynBufferMut<'a> {\n+    unsafe fn pointer_mut(&mut self) -> *mut c_void {\n+        self.ptr\n+    }\n+}\n+\n+unsafe impl<'a> Buffer for DynBufferMut<'a> {}\n+\n+unsafe impl<'a> BufferMut for DynBufferMut<'a> {}\n+\n+unsafe impl<'a> AsDatatype for DynBufferMut<'a> {\n+    type Out = BorrowedDatatype<'a>;\n+    fn as_datatype(&self) -> Self::Out {\n+        self.datatype\n+    }\n+}\n+\n+impl<'a> DynBufferMut<'a> {\n+    /// Creates a mutable buffer from a mutable slice with whose type has an MPI equivalent.\n+    pub fn new_mut<T: Equivalence>(buf: &'a mut [T]) -> Self {\n+        unsafe {\n+            let datatype = BorrowedDatatype::from_raw(\n+                T::equivalent_datatype().as_raw());\n+            Self::from_raw_mut(buf.as_mut_ptr(), buf.count(), datatype)\n+        }\n+    }\n+\n+    /// Tests whether the buffer type matches `T`.\n+    pub fn is<T: Equivalence>(&self) -> bool {\n+        self.as_datatype().as_raw() == T::equivalent_datatype().as_raw()\n+    }\n+\n+    /// Returns some slice if the type matches `T`, or `None` if it doesn't.\n+    pub fn downcast<T: Equivalence>(&self) -> Option<&[T]> {\n+        if self.is::<T>() {\n+            unsafe { Some(slice::from_raw_parts(self.as_ptr() as _, self.len())) }\n+        } else {\n+            None\n+        }\n+    }\n+\n+    /// Returns some mutable slice if the type matches `T`, or `None` if it doesn't.\n+    pub fn downcast_mut<T: Equivalence>(&mut self) -> Option<&mut [T]> {\n+        if self.is::<T>() {\n+            unsafe { Some(slice::from_raw_parts_mut(self.as_mut_ptr() as _, self.len())) }\n+        } else {\n+            None\n+        }\n+    }\n+\n+    /// Creates a buffer from its raw components.  The buffer must remain valid for `'a`.\n+    pub unsafe fn from_raw_mut<T>(ptr: *mut T,","path":"src/datatype.rs","position":231,"original_position":231,"commit_id":"32a7b326c737eacd773d0241a4c69bed57f1407d","original_commit_id":"32a7b326c737eacd773d0241a4c69bed57f1407d","user":{"login":"bsteinb","id":3883096,"avatar_url":"https://avatars2.githubusercontent.com/u/3883096?v=3","gravatar_id":"","url":"https://api.github.com/users/bsteinb","html_url":"https://github.com/bsteinb","followers_url":"https://api.github.com/users/bsteinb/followers","following_url":"https://api.github.com/users/bsteinb/following{/other_user}","gists_url":"https://api.github.com/users/bsteinb/gists{/gist_id}","starred_url":"https://api.github.com/users/bsteinb/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bsteinb/subscriptions","organizations_url":"https://api.github.com/users/bsteinb/orgs","repos_url":"https://api.github.com/users/bsteinb/repos","events_url":"https://api.github.com/users/bsteinb/events{/privacy}","received_events_url":"https://api.github.com/users/bsteinb/received_events","type":"User","site_admin":false},"body":"Why not just `from_raw`?","created_at":"2017-05-25T20:04:21Z","updated_at":"2017-05-25T20:12:37Z","html_url":"https://github.com/bsteinb/rsmpi/pull/25#discussion_r118572250","pull_request_url":"https://api.github.com/repos/bsteinb/rsmpi/pulls/25","_links":{"self":{"href":"https://api.github.com/repos/bsteinb/rsmpi/pulls/comments/118572250"},"html":{"href":"https://github.com/bsteinb/rsmpi/pull/25#discussion_r118572250"},"pull_request":{"href":"https://api.github.com/repos/bsteinb/rsmpi/pulls/25"}}},"pull_request":{"url":"https://api.github.com/repos/bsteinb/rsmpi/pulls/25","id":122359390,"html_url":"https://github.com/bsteinb/rsmpi/pull/25","diff_url":"https://github.com/bsteinb/rsmpi/pull/25.diff","patch_url":"https://github.com/bsteinb/rsmpi/pull/25.patch","issue_url":"https://api.github.com/repos/bsteinb/rsmpi/issues/25","number":25,"state":"open","locked":false,"title":"Add support for user-defined operations","user":{"login":"Rufflewind","id":6571068,"avatar_url":"https://avatars0.githubusercontent.com/u/6571068?v=3","gravatar_id":"","url":"https://api.github.com/users/Rufflewind","html_url":"https://github.com/Rufflewind","followers_url":"https://api.github.com/users/Rufflewind/followers","following_url":"https://api.github.com/users/Rufflewind/following{/other_user}","gists_url":"https://api.github.com/users/Rufflewind/gists{/gist_id}","starred_url":"https://api.github.com/users/Rufflewind/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Rufflewind/subscriptions","organizations_url":"https://api.github.com/users/Rufflewind/orgs","repos_url":"https://api.github.com/users/Rufflewind/repos","events_url":"https://api.github.com/users/Rufflewind/events{/privacy}","received_events_url":"https://api.github.com/users/Rufflewind/received_events","type":"User","site_admin":false},"body":"It’s not pretty …  Because of how MPI_User_function is defined, it doesn’t give us a clean way attach/access arbitrary user data.  As a result, we have to pull in libffi to hack our way through.\r\n\r\n- Add `BorrowedDatatype`, a thin wrapper over `MPI_Datatype` (feel free to bikeshed on the name)\r\n- Redefine `SystemDatatype = BorrowedDatatype<'static>`\r\n- Add `DynBuffer[Mut]`\r\n- Add `is_commutative`\r\n- Add `UserOperation`","created_at":"2017-05-25T02:15:36Z","updated_at":"2017-05-25T20:12:37Z","closed_at":null,"merged_at":null,"merge_commit_sha":"8a9a70a0f348ef1d7514c8a0b47590319c6621af","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/bsteinb/rsmpi/pulls/25/commits","review_comments_url":"https://api.github.com/repos/bsteinb/rsmpi/pulls/25/comments","review_comment_url":"https://api.github.com/repos/bsteinb/rsmpi/pulls/comments{/number}","comments_url":"https://api.github.com/repos/bsteinb/rsmpi/issues/25/comments","statuses_url":"https://api.github.com/repos/bsteinb/rsmpi/statuses/32a7b326c737eacd773d0241a4c69bed57f1407d","head":{"label":"Rufflewind:operation","ref":"operation","sha":"32a7b326c737eacd773d0241a4c69bed57f1407d","user":{"login":"Rufflewind","id":6571068,"avatar_url":"https://avatars0.githubusercontent.com/u/6571068?v=3","gravatar_id":"","url":"https://api.github.com/users/Rufflewind","html_url":"https://github.com/Rufflewind","followers_url":"https://api.github.com/users/Rufflewind/followers","following_url":"https://api.github.com/users/Rufflewind/following{/other_user}","gists_url":"https://api.github.com/users/Rufflewind/gists{/gist_id}","starred_url":"https://api.github.com/users/Rufflewind/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Rufflewind/subscriptions","organizations_url":"https://api.github.com/users/Rufflewind/orgs","repos_url":"https://api.github.com/users/Rufflewind/repos","events_url":"https://api.github.com/users/Rufflewind/events{/privacy}","received_events_url":"https://api.github.com/users/Rufflewind/received_events","type":"User","site_admin":false},"repo":{"id":85785263,"name":"rsmpi","full_name":"Rufflewind/rsmpi","owner":{"login":"Rufflewind","id":6571068,"avatar_url":"https://avatars0.githubusercontent.com/u/6571068?v=3","gravatar_id":"","url":"https://api.github.com/users/Rufflewind","html_url":"https://github.com/Rufflewind","followers_url":"https://api.github.com/users/Rufflewind/followers","following_url":"https://api.github.com/users/Rufflewind/following{/other_user}","gists_url":"https://api.github.com/users/Rufflewind/gists{/gist_id}","starred_url":"https://api.github.com/users/Rufflewind/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Rufflewind/subscriptions","organizations_url":"https://api.github.com/users/Rufflewind/orgs","repos_url":"https://api.github.com/users/Rufflewind/repos","events_url":"https://api.github.com/users/Rufflewind/events{/privacy}","received_events_url":"https://api.github.com/users/Rufflewind/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/Rufflewind/rsmpi","description":"MPI bindings for Rust","fork":true,"url":"https://api.github.com/repos/Rufflewind/rsmpi","forks_url":"https://api.github.com/repos/Rufflewind/rsmpi/forks","keys_url":"https://api.github.com/repos/Rufflewind/rsmpi/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Rufflewind/rsmpi/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Rufflewind/rsmpi/teams","hooks_url":"https://api.github.com/repos/Rufflewind/rsmpi/hooks","issue_events_url":"https://api.github.com/repos/Rufflewind/rsmpi/issues/events{/number}","events_url":"https://api.github.com/repos/Rufflewind/rsmpi/events","assignees_url":"https://api.github.com/repos/Rufflewind/rsmpi/assignees{/user}","branches_url":"https://api.github.com/repos/Rufflewind/rsmpi/branches{/branch}","tags_url":"https://api.github.com/repos/Rufflewind/rsmpi/tags","blobs_url":"https://api.github.com/repos/Rufflewind/rsmpi/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Rufflewind/rsmpi/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Rufflewind/rsmpi/git/refs{/sha}","trees_url":"https://api.github.com/repos/Rufflewind/rsmpi/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Rufflewind/rsmpi/statuses/{sha}","languages_url":"https://api.github.com/repos/Rufflewind/rsmpi/languages","stargazers_url":"https://api.github.com/repos/Rufflewind/rsmpi/stargazers","contributors_url":"https://api.github.com/repos/Rufflewind/rsmpi/contributors","subscribers_url":"https://api.github.com/repos/Rufflewind/rsmpi/subscribers","subscription_url":"https://api.github.com/repos/Rufflewind/rsmpi/subscription","commits_url":"https://api.github.com/repos/Rufflewind/rsmpi/commits{/sha}","git_commits_url":"https://api.github.com/repos/Rufflewind/rsmpi/git/commits{/sha}","comments_url":"https://api.github.com/repos/Rufflewind/rsmpi/comments{/number}","issue_comment_url":"https://api.github.com/repos/Rufflewind/rsmpi/issues/comments{/number}","contents_url":"https://api.github.com/repos/Rufflewind/rsmpi/contents/{+path}","compare_url":"https://api.github.com/repos/Rufflewind/rsmpi/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Rufflewind/rsmpi/merges","archive_url":"https://api.github.com/repos/Rufflewind/rsmpi/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Rufflewind/rsmpi/downloads","issues_url":"https://api.github.com/repos/Rufflewind/rsmpi/issues{/number}","pulls_url":"https://api.github.com/repos/Rufflewind/rsmpi/pulls{/number}","milestones_url":"https://api.github.com/repos/Rufflewind/rsmpi/milestones{/number}","notifications_url":"https://api.github.com/repos/Rufflewind/rsmpi/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Rufflewind/rsmpi/labels{/name}","releases_url":"https://api.github.com/repos/Rufflewind/rsmpi/releases{/id}","deployments_url":"https://api.github.com/repos/Rufflewind/rsmpi/deployments","created_at":"2017-03-22T04:33:50Z","updated_at":"2017-03-22T04:33:52Z","pushed_at":"2017-05-25T20:11:02Z","git_url":"git://github.com/Rufflewind/rsmpi.git","ssh_url":"git@github.com:Rufflewind/rsmpi.git","clone_url":"https://github.com/Rufflewind/rsmpi.git","svn_url":"https://github.com/Rufflewind/rsmpi","homepage":"http://bsteinb.github.io/rsmpi/","size":350,"stargazers_count":0,"watchers_count":0,"language":"Rust","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"bsteinb:master","ref":"master","sha":"36493c4fd805f684920700e0ce8de07fcd7b8e68","user":{"login":"bsteinb","id":3883096,"avatar_url":"https://avatars2.githubusercontent.com/u/3883096?v=3","gravatar_id":"","url":"https://api.github.com/users/bsteinb","html_url":"https://github.com/bsteinb","followers_url":"https://api.github.com/users/bsteinb/followers","following_url":"https://api.github.com/users/bsteinb/following{/other_user}","gists_url":"https://api.github.com/users/bsteinb/gists{/gist_id}","starred_url":"https://api.github.com/users/bsteinb/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bsteinb/subscriptions","organizations_url":"https://api.github.com/users/bsteinb/orgs","repos_url":"https://api.github.com/users/bsteinb/repos","events_url":"https://api.github.com/users/bsteinb/events{/privacy}","received_events_url":"https://api.github.com/users/bsteinb/received_events","type":"User","site_admin":false},"repo":{"id":39469270,"name":"rsmpi","full_name":"bsteinb/rsmpi","owner":{"login":"bsteinb","id":3883096,"avatar_url":"https://avatars2.githubusercontent.com/u/3883096?v=3","gravatar_id":"","url":"https://api.github.com/users/bsteinb","html_url":"https://github.com/bsteinb","followers_url":"https://api.github.com/users/bsteinb/followers","following_url":"https://api.github.com/users/bsteinb/following{/other_user}","gists_url":"https://api.github.com/users/bsteinb/gists{/gist_id}","starred_url":"https://api.github.com/users/bsteinb/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bsteinb/subscriptions","organizations_url":"https://api.github.com/users/bsteinb/orgs","repos_url":"https://api.github.com/users/bsteinb/repos","events_url":"https://api.github.com/users/bsteinb/events{/privacy}","received_events_url":"https://api.github.com/users/bsteinb/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/bsteinb/rsmpi","description":"MPI bindings for Rust","fork":false,"url":"https://api.github.com/repos/bsteinb/rsmpi","forks_url":"https://api.github.com/repos/bsteinb/rsmpi/forks","keys_url":"https://api.github.com/repos/bsteinb/rsmpi/keys{/key_id}","collaborators_url":"https://api.github.com/repos/bsteinb/rsmpi/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/bsteinb/rsmpi/teams","hooks_url":"https://api.github.com/repos/bsteinb/rsmpi/hooks","issue_events_url":"https://api.github.com/repos/bsteinb/rsmpi/issues/events{/number}","events_url":"https://api.github.com/repos/bsteinb/rsmpi/events","assignees_url":"https://api.github.com/repos/bsteinb/rsmpi/assignees{/user}","branches_url":"https://api.github.com/repos/bsteinb/rsmpi/branches{/branch}","tags_url":"https://api.github.com/repos/bsteinb/rsmpi/tags","blobs_url":"https://api.github.com/repos/bsteinb/rsmpi/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/bsteinb/rsmpi/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/bsteinb/rsmpi/git/refs{/sha}","trees_url":"https://api.github.com/repos/bsteinb/rsmpi/git/trees{/sha}","statuses_url":"https://api.github.com/repos/bsteinb/rsmpi/statuses/{sha}","languages_url":"https://api.github.com/repos/bsteinb/rsmpi/languages","stargazers_url":"https://api.github.com/repos/bsteinb/rsmpi/stargazers","contributors_url":"https://api.github.com/repos/bsteinb/rsmpi/contributors","subscribers_url":"https://api.github.com/repos/bsteinb/rsmpi/subscribers","subscription_url":"https://api.github.com/repos/bsteinb/rsmpi/subscription","commits_url":"https://api.github.com/repos/bsteinb/rsmpi/commits{/sha}","git_commits_url":"https://api.github.com/repos/bsteinb/rsmpi/git/commits{/sha}","comments_url":"https://api.github.com/repos/bsteinb/rsmpi/comments{/number}","issue_comment_url":"https://api.github.com/repos/bsteinb/rsmpi/issues/comments{/number}","contents_url":"https://api.github.com/repos/bsteinb/rsmpi/contents/{+path}","compare_url":"https://api.github.com/repos/bsteinb/rsmpi/compare/{base}...{head}","merges_url":"https://api.github.com/repos/bsteinb/rsmpi/merges","archive_url":"https://api.github.com/repos/bsteinb/rsmpi/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/bsteinb/rsmpi/downloads","issues_url":"https://api.github.com/repos/bsteinb/rsmpi/issues{/number}","pulls_url":"https://api.github.com/repos/bsteinb/rsmpi/pulls{/number}","milestones_url":"https://api.github.com/repos/bsteinb/rsmpi/milestones{/number}","notifications_url":"https://api.github.com/repos/bsteinb/rsmpi/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/bsteinb/rsmpi/labels{/name}","releases_url":"https://api.github.com/repos/bsteinb/rsmpi/releases{/id}","deployments_url":"https://api.github.com/repos/bsteinb/rsmpi/deployments","created_at":"2015-07-21T20:51:28Z","updated_at":"2017-05-17T18:20:20Z","pushed_at":"2017-05-25T03:13:52Z","git_url":"git://github.com/bsteinb/rsmpi.git","ssh_url":"git@github.com:bsteinb/rsmpi.git","clone_url":"https://github.com/bsteinb/rsmpi.git","svn_url":"https://github.com/bsteinb/rsmpi","homepage":"http://bsteinb.github.io/rsmpi/","size":1422,"stargazers_count":49,"watchers_count":49,"language":"Rust","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":8,"mirror_url":null,"open_issues_count":4,"forks":8,"open_issues":4,"watchers":49,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/bsteinb/rsmpi/pulls/25"},"html":{"href":"https://github.com/bsteinb/rsmpi/pull/25"},"issue":{"href":"https://api.github.com/repos/bsteinb/rsmpi/issues/25"},"comments":{"href":"https://api.github.com/repos/bsteinb/rsmpi/issues/25/comments"},"review_comments":{"href":"https://api.github.com/repos/bsteinb/rsmpi/pulls/25/comments"},"review_comment":{"href":"https://api.github.com/repos/bsteinb/rsmpi/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/bsteinb/rsmpi/pulls/25/commits"},"statuses":{"href":"https://api.github.com/repos/bsteinb/rsmpi/statuses/32a7b326c737eacd773d0241a4c69bed57f1407d"}}}}
{"actor":{"display_login":"bsteinb"}}