Skip to main content

zrx_stream/stream/function/argument/
splat.rs

1// Copyright (c) 2025-2026 Zensical and contributors
2
3// SPDX-License-Identifier: MIT
4// All contributions are certified under the DCO
5
6// Permission is hereby granted, free of charge, to any person obtaining a copy
7// of this software and associated documentation files (the "Software"), to
8// deal in the Software without restriction, including without limitation the
9// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10// sell copies of the Software, and to permit persons to whom the Software is
11// furnished to do so, subject to the following conditions:
12
13// The above copyright notice and this permission notice shall be included in
14// all copies or substantial portions of the Software.
15
16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
19// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22// IN THE SOFTWARE.
23
24// ----------------------------------------------------------------------------
25
26//! Splat argument.
27
28use std::ptr;
29
30// ----------------------------------------------------------------------------
31// Structs
32// ----------------------------------------------------------------------------
33
34/// Splat argument.
35///
36/// This is a marker trait that is used as a wrapper around tuples of arguments
37/// allowing to invoke a function with multiple arguments as if it were a single
38/// argument. Its purpose is to make writing operators with multiple arguments
39/// more ergonomic, which is particularly useful for joins.
40///
41/// All function traits implement variations of [`Splat`] for tuples of up to 8
42/// elements, which is likely to be sufficient for most use cases. Please note
43/// that most of the time, this type is only ever needed for creating flexible
44/// operator functions, so you'll rarely want to use it directly. Additionally,
45/// note that [`Splat`] itself doesn't impose any trait bounds in order to not
46/// require even more trait bounds in the signature of implementors. Moreover,
47/// it doesn't implement [`Value`][], meaning it can only be used temporarily
48/// inside operators, but never returned.
49///
50/// [`Value`]:  zrx_scheduler::Value
51///
52/// # Examples
53///
54/// ```
55/// use zrx_stream::function::Splat;
56///
57/// // Create splat from tuple
58/// let splat = Splat::from((1, 2));
59/// ```
60#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
61#[repr(transparent)] // do not remove
62pub struct Splat<T> {
63    /// Inner arguments.
64    inner: T,
65}
66
67// ----------------------------------------------------------------------------
68// Implementations
69// ----------------------------------------------------------------------------
70
71impl<T> Splat<T> {
72    /// Returns the inner tuple of arguments.
73    ///
74    /// # Examples
75    ///
76    /// ```
77    /// use zrx_stream::function::Splat;
78    ///
79    /// // Create splat from tuple
80    /// let splat = Splat::from((1, 2));
81    /// assert_eq!(splat.inner(), &(1, 2));
82    /// ```
83    #[inline]
84    pub fn inner(&self) -> &T {
85        &self.inner
86    }
87
88    /// Returns the inner tuple of arguments, consuming the splat.
89    ///
90    /// # Examples
91    ///
92    /// ```
93    /// use zrx_stream::function::Splat;
94    ///
95    /// // Create splat from tuple
96    /// let splat = Splat::from((1, 2));
97    /// assert_eq!(splat.into_inner(), (1, 2));
98    /// ```
99    #[inline]
100    pub fn into_inner(self) -> T {
101        self.inner
102    }
103}
104
105impl<T> Splat<T> {
106    /// Creates a splat argument from a reference to a tuple.
107    ///
108    /// This method converts `&T` to `&Splat<T>`, which allows us to use splat
109    /// arguments in any function that takes a reference to a value `T` without
110    /// cloning the value. While the conversion mandates the use of `unsafe`,
111    /// it's safe due to identical memory layout guarantees.
112    ///
113    /// # Examples
114    ///
115    /// ```
116    /// use zrx_stream::function::Splat;
117    ///
118    /// // Create splat from tuple reference
119    /// let splat = Splat::from_ref(&(1, 2));
120    /// ```
121    #[inline]
122    pub fn from_ref(inner: &T) -> &Self {
123        // SAFETY: `repr(transparent)` guarantees that the type is transparent,
124        // meaning the outer type has the same memory layout as the inner type
125        unsafe { &*ptr::from_ref(inner).cast() }
126    }
127}
128
129// ----------------------------------------------------------------------------
130
131impl<T> From<T> for Splat<T> {
132    /// Creates a splat from a tuple of arguments.
133    ///
134    /// # Examples
135    ///
136    /// ```
137    /// use zrx_stream::function::Splat;
138    ///
139    /// // Create splat from tuple
140    /// let splat = Splat::from((1, 2));
141    /// ```
142    #[inline]
143    fn from(inner: T) -> Self {
144        Self { inner }
145    }
146}