cardano_sdk/cardano/
input.rs

1//  This Source Code Form is subject to the terms of the Mozilla Public
2//  License, v. 2.0. If a copy of the MPL was not distributed with this
3//  file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5use crate::{Hash, cbor, pallas};
6use anyhow::anyhow;
7use std::{fmt, str::FromStr, sync::Arc};
8
9/// A reference to a past transaction output.
10#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
11#[repr(transparent)]
12pub struct Input(Arc<pallas::TransactionInput>);
13
14impl fmt::Display for Input {
15    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16        write!(f, "Input({}#{})", &self.0.transaction_id, self.0.index)
17    }
18}
19
20// -------------------------------------------------------------------- Building
21
22impl Input {
23    /// See also [`input!`](crate::input).
24    pub fn new(transaction_id: Hash<32>, output_index: u64) -> Self {
25        Self(Arc::new(pallas::TransactionInput {
26            transaction_id: pallas::Hash::from(transaction_id),
27            index: output_index,
28        }))
29    }
30}
31
32// ------------------------------------------------------------------ Inspecting
33
34impl Input {
35    pub fn transaction_id(&self) -> Hash<32> {
36        Hash::from(self.0.transaction_id)
37    }
38
39    pub fn output_index(&self) -> u64 {
40        self.0.index
41    }
42}
43
44// ----------------------------------------------------------- Converting (from)
45
46impl From<pallas::TransactionInput> for Input {
47    fn from(i: pallas::TransactionInput) -> Self {
48        Input(Arc::new(i))
49    }
50}
51
52impl FromStr for Input {
53    type Err = anyhow::Error;
54
55    fn from_str(s: &str) -> anyhow::Result<Self> {
56        let mut split = s.split("#");
57
58        let transaction_id = split.next().ok_or(anyhow!("missing transaction id"))?;
59
60        let index = split.next().ok_or(anyhow!("missing output index"))?;
61
62        if split.next().is_some() {
63            return Err(anyhow!("leftovers after output index"));
64        }
65
66        Ok(Self::new(
67            <Hash<32>>::try_from(transaction_id)?,
68            index.parse::<u64>()?,
69        ))
70    }
71}
72
73// ------------------------------------------------------------- Converting (to)
74
75impl From<Input> for pallas::TransactionInput {
76    fn from(i: Input) -> Self {
77        Arc::unwrap_or_clone(i.0)
78    }
79}
80
81// -------------------------------------------------------------------- Encoding
82
83impl<C> cbor::Encode<C> for Input {
84    fn encode<W: cbor::encode::write::Write>(
85        &self,
86        e: &mut cbor::Encoder<W>,
87        ctx: &mut C,
88    ) -> Result<(), cbor::encode::Error<W::Error>> {
89        e.encode_with(self.0.as_ref(), ctx)?;
90        Ok(())
91    }
92}
93
94impl<'d, C> cbor::Decode<'d, C> for Input {
95    fn decode(d: &mut cbor::Decoder<'d>, ctx: &mut C) -> Result<Self, cbor::decode::Error> {
96        Ok(Self(Arc::new(d.decode_with(ctx)?)))
97    }
98}
99
100#[cfg(any(test, feature = "test-utils"))]
101pub mod tests {
102    use crate::{Input, any, hash};
103    use proptest::prelude::*;
104
105    // -------------------------------------------------------------- Unit tests
106
107    #[test]
108    fn display_input() {
109        assert_eq!(
110            Input::new(
111                hash!("702206530b2e1566e90b3aec753bd0abbf397842bd5421e0c3d23ed10167b3ce"),
112                42,
113            )
114            .to_string(),
115            "Input(702206530b2e1566e90b3aec753bd0abbf397842bd5421e0c3d23ed10167b3ce#42)",
116        );
117    }
118
119    // -------------------------------------------------------------- Generators
120
121    pub mod generators {
122        use super::*;
123
124        prop_compose! {
125            pub fn input()(id in any::hash32(), ix in any::<u64>()) -> Input {
126                Input::new(id, ix)
127            }
128        }
129    }
130}