libcst_native/nodes/
traits.rs

1// Copyright (c) Meta Platforms, Inc. and affiliates.
2//
3// This source code is licensed under the MIT license found in the
4// LICENSE file in the root directory of this source tree
5
6use crate::{
7    nodes::expression::{DeflatedLeftParen, DeflatedRightParen},
8    nodes::op::DeflatedComma,
9    tokenizer::whitespace_parser::{Config, WhitespaceError},
10    Codegen, CodegenState, EmptyLine, LeftParen, RightParen,
11};
12use std::ops::Deref;
13
14pub trait WithComma<'r, 'a> {
15    fn with_comma(self, comma: DeflatedComma<'r, 'a>) -> Self;
16}
17
18pub trait ParenthesizedNode<'a> {
19    fn lpar(&self) -> &Vec<LeftParen<'a>>;
20    fn rpar(&self) -> &Vec<RightParen<'a>>;
21
22    fn parenthesize<F>(&self, state: &mut CodegenState<'a>, f: F)
23    where
24        F: FnOnce(&mut CodegenState<'a>),
25    {
26        for lpar in self.lpar() {
27            lpar.codegen(state);
28        }
29        f(state);
30        for rpar in self.rpar() {
31            rpar.codegen(state);
32        }
33    }
34
35    fn with_parens(self, left: LeftParen<'a>, right: RightParen<'a>) -> Self;
36}
37
38impl<'a, T: ParenthesizedNode<'a>> ParenthesizedNode<'a> for Box<T> {
39    fn lpar(&self) -> &Vec<LeftParen<'a>> {
40        self.deref().lpar()
41    }
42    fn rpar(&self) -> &Vec<RightParen<'a>> {
43        self.deref().rpar()
44    }
45    fn parenthesize<F>(&self, state: &mut CodegenState<'a>, f: F)
46    where
47        F: FnOnce(&mut CodegenState<'a>),
48    {
49        self.deref().parenthesize(state, f)
50    }
51    fn with_parens(self, left: LeftParen<'a>, right: RightParen<'a>) -> Self {
52        Self::new((*self).with_parens(left, right))
53    }
54}
55
56pub trait ParenthesizedDeflatedNode<'r, 'a> {
57    fn lpar(&self) -> &Vec<DeflatedLeftParen<'r, 'a>>;
58    fn rpar(&self) -> &Vec<DeflatedRightParen<'r, 'a>>;
59
60    fn with_parens(
61        self,
62        left: DeflatedLeftParen<'r, 'a>,
63        right: DeflatedRightParen<'r, 'a>,
64    ) -> Self;
65}
66impl<'r, 'a, T: ParenthesizedDeflatedNode<'r, 'a>> ParenthesizedDeflatedNode<'r, 'a> for Box<T> {
67    fn lpar(&self) -> &Vec<DeflatedLeftParen<'r, 'a>> {
68        self.deref().lpar()
69    }
70    fn rpar(&self) -> &Vec<DeflatedRightParen<'r, 'a>> {
71        self.deref().rpar()
72    }
73    fn with_parens(
74        self,
75        left: DeflatedLeftParen<'r, 'a>,
76        right: DeflatedRightParen<'r, 'a>,
77    ) -> Self {
78        Self::new((*self).with_parens(left, right))
79    }
80}
81
82pub trait WithLeadingLines<'a> {
83    fn leading_lines(&mut self) -> &mut Vec<EmptyLine<'a>>;
84}
85
86pub type Result<T> = std::result::Result<T, WhitespaceError>;
87
88pub trait Inflate<'a>
89where
90    Self: Sized,
91{
92    type Inflated;
93    fn inflate(self, config: &Config<'a>) -> Result<Self::Inflated>;
94}
95
96impl<'a, T: Inflate<'a>> Inflate<'a> for Option<T> {
97    type Inflated = Option<T::Inflated>;
98    fn inflate(self, config: &Config<'a>) -> Result<Self::Inflated> {
99        self.map(|x| x.inflate(config)).transpose()
100    }
101}
102
103impl<'a, T: Inflate<'a> + ?Sized> Inflate<'a> for Box<T> {
104    type Inflated = Box<T::Inflated>;
105    fn inflate(self, config: &Config<'a>) -> Result<Self::Inflated> {
106        match (*self).inflate(config) {
107            Ok(a) => Ok(Box::new(a)),
108            Err(e) => Err(e),
109        }
110    }
111}
112
113impl<'a, T: Inflate<'a>> Inflate<'a> for Vec<T> {
114    type Inflated = Vec<T::Inflated>;
115    fn inflate(self, config: &Config<'a>) -> Result<Self::Inflated> {
116        self.into_iter().map(|item| item.inflate(config)).collect()
117    }
118}
119#[cfg(feature = "py")]
120pub mod py {
121    use pyo3::{types::PyTuple, IntoPyObjectExt, Py, PyAny, PyResult, Python};
122
123    // TODO: replace with upstream implementation once
124    // https://github.com/PyO3/pyo3/issues/1813 is resolved
125    pub trait TryIntoPy<T>: Sized {
126        fn try_into_py(self, py: Python) -> PyResult<T>;
127    }
128
129    // I wish:
130    // impl<PyT, T: IntoPy<PyT>> TryIntoPy<PyT> for T {
131    //     fn try_into_py(self, py: Python) -> PyResult<PyT> {
132    //         Ok(self.into_py(py))
133    //     }
134    // }
135
136    impl TryIntoPy<Py<PyAny>> for bool {
137        fn try_into_py(self, py: Python) -> PyResult<Py<PyAny>> {
138            self.into_py_any(py)
139        }
140    }
141
142    impl<T: TryIntoPy<Py<PyAny>>> TryIntoPy<Py<PyAny>> for Box<T>
143    where
144        T: TryIntoPy<Py<PyAny>>,
145    {
146        fn try_into_py(self, py: Python) -> PyResult<Py<PyAny>> {
147            (*self).try_into_py(py)
148        }
149    }
150
151    impl<T> TryIntoPy<Py<PyAny>> for Option<T>
152    where
153        T: TryIntoPy<Py<PyAny>>,
154    {
155        fn try_into_py(self, py: Python) -> PyResult<Py<PyAny>> {
156            Ok(match self {
157                None => py.None(),
158                Some(x) => x.try_into_py(py)?,
159            })
160        }
161    }
162
163    impl<T> TryIntoPy<Py<PyAny>> for Vec<T>
164    where
165        T: TryIntoPy<Py<PyAny>>,
166    {
167        fn try_into_py(self, py: Python) -> PyResult<Py<PyAny>> {
168            let converted = self
169                .into_iter()
170                .map(|x| x.try_into_py(py))
171                .collect::<PyResult<Vec<_>>>()?
172                .into_iter();
173            PyTuple::new(py, converted)?.into_py_any(py)
174        }
175    }
176
177    impl<'a> TryIntoPy<Py<PyAny>> for &'a str {
178        fn try_into_py(self, py: Python) -> PyResult<Py<PyAny>> {
179            self.into_py_any(py)
180        }
181    }
182}