Skip to main content

libperl_rs/
cop.rs

1//! `Cop` newtype — a non-null handle to a Perl `COP` ("control op":
2//! the `nextstate` / `dbstate` statement-boundary ops that carry
3//! source location). This is the source↔OP mapping piece of Step 2 —
4//! `CopFILE` / `CopLINE` extraction per `docs/plan/README.md` §4
5//! Step 3.3, promoted into the newtype layer.
6//!
7//! Obtain one via [`Op::as_cop`](crate::Op::as_cop) (class-checked) or
8//! [`Cv::first_cop`](crate::Cv::first_cop).
9
10use std::ptr::NonNull;
11
12use libperl_sys::COP;
13
14/// Non-null pointer to a Perl `COP`. Same ABI as `*mut COP`.
15/// Non-owning, like the other newtypes.
16#[derive(Clone, Copy)]
17#[repr(transparent)]
18pub struct Cop(NonNull<COP>);
19
20impl Cop {
21    /// Wrap a raw COP pointer without checking for null.
22    ///
23    /// # Safety
24    /// Caller must guarantee `p` is non-null and points to a valid
25    /// COP for at least the lifetime of the resulting `Cop`. Prefer
26    /// [`Op::as_cop`](crate::Op::as_cop), which class-checks first.
27    #[inline]
28    pub unsafe fn from_raw_unchecked(p: *const COP) -> Self {
29        debug_assert!(!p.is_null(), "Cop::from_raw_unchecked received a null pointer");
30        Cop(unsafe { NonNull::new_unchecked(p as *mut COP) })
31    }
32
33    /// Wrap a raw COP pointer, returning `None` on null input.
34    #[inline]
35    pub fn from_raw(p: *const COP) -> Option<Self> {
36        NonNull::new(p as *mut COP).map(Cop)
37    }
38
39    /// Raw pointer for FFI calls.
40    #[inline]
41    pub fn as_ptr(&self) -> *mut COP {
42        self.0.as_ptr()
43    }
44
45    /// Source line of the statement this COP opens (`CopLINE`).
46    #[inline]
47    pub fn line(&self) -> u32 {
48        unsafe { libperl_sys::CopLINE(self.0.as_ptr()) }
49    }
50
51    /// Source file of the statement (`CopFILE`); `"-e"` for one-liner
52    /// scripts, `"(eval N)"` inside string evals.
53    pub fn file(&self) -> Option<String> {
54        let p = unsafe { libperl_sys::CopFILE(self.0.as_ptr()) };
55        if p.is_null() {
56            None
57        } else {
58            Some(
59                unsafe { std::ffi::CStr::from_ptr(p) }
60                    .to_string_lossy()
61                    .into_owned(),
62            )
63        }
64    }
65}