@@ -88,6 +88,15 @@ impl Header {
8888 }
8989 }
9090
91+ /// Get a pointer to the raw header.
92+ ///
93+ /// # Safety
94+ /// The caller must ensure that the pointer is not used after this `Header`
95+ /// is dropped
96+ pub unsafe fn inner_ptr ( & self ) -> * mut htslib:: bcf_hdr_t {
97+ self . inner
98+ }
99+
91100 /// Create a new `Header` using the given `HeaderView` as the template.
92101 ///
93102 /// After construction, you can modify the header independently from the template `header`.
@@ -276,10 +285,23 @@ unsafe impl Send for HeaderView {}
276285unsafe impl Sync for HeaderView { }
277286
278287impl HeaderView {
279- pub ( crate ) fn new ( inner : * mut htslib:: bcf_hdr_t ) -> Self {
288+ /// Create a view from a raw pointer to a header.
289+ ///
290+ /// # Safety
291+ /// The caller must ensure that the header is initialized.
292+ pub unsafe fn from_ptr ( inner : * mut htslib:: bcf_hdr_t ) -> Self {
280293 HeaderView { inner }
281294 }
282295
296+ /// Get a pointer to the underlying raw header.
297+ ///
298+ /// # Safety
299+ /// The caller must ensure that the pointer is not used after this
300+ /// `HeaderView` is dropped
301+ pub unsafe fn as_ptr ( & self ) -> * mut htslib:: bcf_hdr_t {
302+ self . inner
303+ }
304+
283305 #[ inline]
284306 fn inner ( & self ) -> htslib:: bcf_hdr_t {
285307 unsafe { * self . inner }
@@ -559,7 +581,9 @@ pub enum TagLength {
559581
560582#[ cfg( test) ]
561583mod tests {
584+ use super :: * ;
562585 use crate :: bcf:: Reader ;
586+ use crate :: htslib;
563587
564588 #[ test]
565589 fn test_header_view_empty_record ( ) {
@@ -576,4 +600,39 @@ mod tests {
576600 assert_eq ! ( record. pos( ) , 0 ) ; // No position set
577601 assert_eq ! ( record. qual( ) , 0.0 ) ; // No quality score set
578602 }
603+
604+ #[ test]
605+ fn test_header_add_sample_via_raw_pointer ( ) {
606+ let sample_name = b"test-sample" ;
607+
608+ let header = Header :: new ( ) ;
609+ let sample = std:: ffi:: CString :: new ( sample_name) . unwrap ( ) ;
610+
611+ let view = unsafe {
612+ let ptr = header. inner_ptr ( ) ;
613+ // to avoid double free, as we will wrap this later in a HeaderView
614+ std:: mem:: forget ( header) ;
615+ htslib:: bcf_hdr_add_sample ( ptr, sample. as_ptr ( ) ) ;
616+ htslib:: bcf_hdr_sync ( ptr) ;
617+ // When the HeaderView is dropped, the bcf_hdr is freed
618+ HeaderView :: from_ptr ( ptr)
619+ } ;
620+
621+ assert_eq ! ( view. samples( ) , vec![ sample_name] ) ;
622+ }
623+
624+ #[ test]
625+ fn test_header_view_version_via_raw_pointer ( ) {
626+ let vcf = Reader :: from_path ( "test/test_string.vcf" ) . expect ( "Error opening file" ) ;
627+ let hv = vcf. header . clone ( ) ;
628+
629+ let version = unsafe {
630+ // the header view will outlive this pointer
631+ let ptr = hv. as_ptr ( ) ;
632+ let version_charptr = htslib:: bcf_hdr_get_version ( ptr) ;
633+ std:: ffi:: CStr :: from_ptr ( version_charptr) . to_str ( ) . unwrap ( )
634+ } ;
635+
636+ assert_eq ! ( version, "VCFv4.1" ) ;
637+ }
579638}
0 commit comments