bitcoin_primitives/script/
borrowed.rs1use core::marker::PhantomData;
4use core::ops::{
5 Bound, Index, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive,
6};
7
8#[cfg(feature = "arbitrary")]
9use arbitrary::{Arbitrary, Unstructured};
10use encoding::{BytesEncoder, CompactSizeEncoder, Encodable, Encoder2};
11
12use super::ScriptBuf;
13use crate::prelude::{Box, ToOwned, Vec};
14
15internals::transparent_newtype! {
16 #[derive(PartialOrd, Ord, PartialEq, Eq, Hash)]
67 pub struct Script<T>(PhantomData<T>, [u8]);
68
69 impl<T> Script<T> {
70 pub const fn from_bytes(bytes: &_) -> &Self;
72
73 pub fn from_bytes_mut(bytes: &mut _) -> &mut Self;
75
76 pub(crate) fn from_boxed_bytes(bytes: Box<_>) -> Box<Self>;
77 pub(crate) fn from_rc_bytes(bytes: Rc<_>) -> Rc<Self>;
78 pub(crate) fn from_arc_bytes(bytes: Arc<_>) -> Arc<Self>;
79 }
80}
81
82impl<T: 'static> Default for &Script<T> {
83 #[inline]
84 fn default() -> Self { Script::new() }
85}
86
87impl<T> ToOwned for Script<T> {
88 type Owned = ScriptBuf<T>;
89
90 #[inline]
91 fn to_owned(&self) -> Self::Owned { ScriptBuf::from_bytes(self.to_vec()) }
92}
93
94impl<T> Script<T> {
95 #[inline]
97 pub const fn new() -> &'static Self { Self::from_bytes(&[]) }
98
99 #[inline]
103 pub const fn as_bytes(&self) -> &[u8] { &self.1 }
104
105 #[inline]
109 pub fn as_mut_bytes(&mut self) -> &mut [u8] { &mut self.1 }
110
111 #[inline]
115 pub fn to_vec(&self) -> Vec<u8> { self.as_bytes().to_owned() }
116
117 #[inline]
119 #[deprecated(since = "0.101.0", note = "use to_vec instead")]
120 pub fn to_bytes(&self) -> Vec<u8> { self.to_vec() }
121
122 #[inline]
124 pub const fn len(&self) -> usize { self.as_bytes().len() }
125
126 #[inline]
128 pub const fn is_empty(&self) -> bool { self.as_bytes().is_empty() }
129
130 #[must_use]
132 #[inline]
133 pub fn into_script_buf(self: Box<Self>) -> ScriptBuf<T> {
134 let rw = Box::into_raw(self) as *mut [u8];
135 let inner = unsafe { Box::from_raw(rw) };
140 ScriptBuf::from_bytes(Vec::from(inner))
141 }
142
143 #[cfg(feature = "alloc")]
150 #[cfg(feature = "hex")]
151 #[inline]
152 #[deprecated(since = "1.0.0-rc.0", note = "use `format!(\"{var:x}\")` instead")]
153 pub fn to_hex(&self) -> alloc::string::String { alloc::format!("{:x}", self) }
154}
155
156encoding::encoder_newtype_exact! {
157 pub struct ScriptEncoder<'e>(Encoder2<CompactSizeEncoder, BytesEncoder<'e>>);
159}
160
161impl<T> Encodable for Script<T> {
162 type Encoder<'e>
163 = ScriptEncoder<'e>
164 where
165 Self: 'e;
166
167 fn encoder(&self) -> Self::Encoder<'_> {
168 ScriptEncoder::new(Encoder2::new(
169 CompactSizeEncoder::new(self.as_bytes().len()),
170 BytesEncoder::without_length_prefix(self.as_bytes()),
171 ))
172 }
173}
174
175#[cfg(feature = "arbitrary")]
176impl<'a, T> Arbitrary<'a> for &'a Script<T> {
177 #[inline]
178 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
179 let v = <&'a [u8]>::arbitrary(u)?;
180 Ok(Script::from_bytes(v))
181 }
182}
183
184macro_rules! delegate_index {
185 ($($type:ty),* $(,)?) => {
186 $(
187 impl<T> Index<$type> for Script<T> {
189 type Output = Self;
190
191 #[inline]
192 fn index(&self, index: $type) -> &Self::Output {
193 Self::from_bytes(&self.as_bytes()[index])
194 }
195 }
196 )*
197 }
198}
199
200delegate_index!(
201 Range<usize>,
202 RangeFrom<usize>,
203 RangeTo<usize>,
204 RangeFull,
205 RangeInclusive<usize>,
206 RangeToInclusive<usize>,
207 (Bound<usize>, Bound<usize>)
208);
209
210#[cfg(test)]
211mod tests {
212 type Script = super::super::ScriptSig;
214
215 #[cfg(feature = "alloc")]
216 use alloc::{borrow::ToOwned, vec};
217
218 #[test]
219 fn script_from_bytes() {
220 let script = Script::from_bytes(&[1, 2, 3]);
221 assert_eq!(script.as_bytes(), [1, 2, 3]);
222 }
223
224 #[test]
225 fn script_from_bytes_mut() {
226 let bytes = &mut [1, 2, 3];
227 let script = Script::from_bytes_mut(bytes);
228 script.as_mut_bytes()[0] = 4;
229 assert_eq!(script.as_mut_bytes(), [4, 2, 3]);
230 }
231
232 #[test]
233 fn script_to_vec() {
234 let script = Script::from_bytes(&[1, 2, 3]);
235 assert_eq!(script.to_vec(), vec![1, 2, 3]);
236 }
237
238 #[test]
239 fn script_len() {
240 let script = Script::from_bytes(&[1, 2, 3]);
241 assert_eq!(script.len(), 3);
242 }
243
244 #[test]
245 fn script_is_empty() {
246 let script: &Script = Default::default();
247 assert!(script.is_empty());
248
249 let script = Script::from_bytes(&[1, 2, 3]);
250 assert!(!script.is_empty());
251 }
252
253 #[test]
254 fn script_to_owned() {
255 let script = Script::from_bytes(&[1, 2, 3]);
256 let script_buf = script.to_owned();
257 assert_eq!(script_buf.as_bytes(), [1, 2, 3]);
258 }
259
260 #[test]
261 fn test_index() {
262 let script = Script::from_bytes(&[1, 2, 3, 4, 5]);
263
264 assert_eq!(script[1..3].as_bytes(), &[2, 3]);
265 assert_eq!(script[2..].as_bytes(), &[3, 4, 5]);
266 assert_eq!(script[..3].as_bytes(), &[1, 2, 3]);
267 assert_eq!(script[..].as_bytes(), &[1, 2, 3, 4, 5]);
268 assert_eq!(script[1..=3].as_bytes(), &[2, 3, 4]);
269 assert_eq!(script[..=2].as_bytes(), &[1, 2, 3]);
270 }
271
272 #[test]
273 #[cfg(feature = "alloc")]
274 fn encode() {
275 let consensus_encoded: [u8; 6] = [0x05, 1, 2, 3, 4, 5];
278
279 let script = Script::from_bytes(&consensus_encoded[1..]);
281
282 let got = encoding::encode_to_vec(script);
283 assert_eq!(got, consensus_encoded);
284 }
285}