Skip to content

Commit 1cb1869

Browse files
committed
feat: Add support for updating existing aux tags inplace.
Add support for updating existing aux tags inplace, by using HTSlib: - bam_aux_update_str - bam_aux_update_int - bam_aux_update_float - bam_aux_update_array functions. Updating aux tags this way will keep the tag at the original location and data of aux tags after get automatically moved if more space was needed when updating a tag inplace.
1 parent d7adb08 commit 1cb1869

File tree

2 files changed

+156
-0
lines changed

2 files changed

+156
-0
lines changed

src/bam/record.rs

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,6 +1068,160 @@ impl Record {
10681068
}
10691069
}
10701070

1071+
/// Update or add auxiliary data.
1072+
pub fn update_aux(&mut self, tag: &[u8], value: Aux<'_>) -> Result<()> {
1073+
// Update existing aux data for the given tag if already present in the record
1074+
// without changing the ordering of tags in the record or append aux data at
1075+
// the end of the existing aux records if it is a new tag.
1076+
1077+
let ctag = tag.as_ptr() as *mut c_char;
1078+
let ret = unsafe {
1079+
match value {
1080+
Aux::Char(_v) => return Err(Error::BamAuxTagUpdatingNotSupported),
1081+
Aux::I8(v) => htslib::bam_aux_update_int(self.inner_ptr_mut(), ctag, v as i64),
1082+
Aux::U8(v) => htslib::bam_aux_update_int(self.inner_ptr_mut(), ctag, v as i64),
1083+
Aux::I16(v) => htslib::bam_aux_update_int(self.inner_ptr_mut(), ctag, v as i64),
1084+
Aux::U16(v) => htslib::bam_aux_update_int(self.inner_ptr_mut(), ctag, v as i64),
1085+
Aux::I32(v) => htslib::bam_aux_update_int(self.inner_ptr_mut(), ctag, v as i64),
1086+
Aux::U32(v) => htslib::bam_aux_update_int(self.inner_ptr_mut(), ctag, v as i64),
1087+
Aux::Float(v) => htslib::bam_aux_update_float(self.inner_ptr_mut(), ctag, v),
1088+
// Not part of specs but implemented in `htslib`:
1089+
Aux::Double(v) => {
1090+
htslib::bam_aux_update_float(self.inner_ptr_mut(), ctag, v as f32)
1091+
}
1092+
Aux::String(v) => {
1093+
let c_str = ffi::CString::new(v).map_err(|_| Error::BamAuxStringError)?;
1094+
htslib::bam_aux_update_str(
1095+
self.inner_ptr_mut(),
1096+
ctag,
1097+
(v.len() + 1) as i32,
1098+
c_str.as_ptr() as *const c_char,
1099+
)
1100+
}
1101+
Aux::HexByteArray(_v) => return Err(Error::BamAuxTagUpdatingNotSupported),
1102+
// Not sure it's safe to cast an immutable slice to a mutable pointer in the following branches
1103+
Aux::ArrayI8(aux_array) => match aux_array {
1104+
AuxArray::TargetType(inner) => htslib::bam_aux_update_array(
1105+
self.inner_ptr_mut(),
1106+
ctag,
1107+
b'c',
1108+
inner.len() as u32,
1109+
inner.slice.as_ptr() as *mut ::libc::c_void,
1110+
),
1111+
AuxArray::RawLeBytes(inner) => htslib::bam_aux_update_array(
1112+
self.inner_ptr_mut(),
1113+
ctag,
1114+
b'c',
1115+
inner.len() as u32,
1116+
inner.slice.as_ptr() as *mut ::libc::c_void,
1117+
),
1118+
},
1119+
Aux::ArrayU8(aux_array) => match aux_array {
1120+
AuxArray::TargetType(inner) => htslib::bam_aux_update_array(
1121+
self.inner_ptr_mut(),
1122+
ctag,
1123+
b'C',
1124+
inner.len() as u32,
1125+
inner.slice.as_ptr() as *mut ::libc::c_void,
1126+
),
1127+
AuxArray::RawLeBytes(inner) => htslib::bam_aux_update_array(
1128+
self.inner_ptr_mut(),
1129+
ctag,
1130+
b'C',
1131+
inner.len() as u32,
1132+
inner.slice.as_ptr() as *mut ::libc::c_void,
1133+
),
1134+
},
1135+
Aux::ArrayI16(aux_array) => match aux_array {
1136+
AuxArray::TargetType(inner) => htslib::bam_aux_update_array(
1137+
self.inner_ptr_mut(),
1138+
ctag,
1139+
b's',
1140+
inner.len() as u32,
1141+
inner.slice.as_ptr() as *mut ::libc::c_void,
1142+
),
1143+
AuxArray::RawLeBytes(inner) => htslib::bam_aux_update_array(
1144+
self.inner_ptr_mut(),
1145+
ctag,
1146+
b's',
1147+
inner.len() as u32,
1148+
inner.slice.as_ptr() as *mut ::libc::c_void,
1149+
),
1150+
},
1151+
Aux::ArrayU16(aux_array) => match aux_array {
1152+
AuxArray::TargetType(inner) => htslib::bam_aux_update_array(
1153+
self.inner_ptr_mut(),
1154+
ctag,
1155+
b'S',
1156+
inner.len() as u32,
1157+
inner.slice.as_ptr() as *mut ::libc::c_void,
1158+
),
1159+
AuxArray::RawLeBytes(inner) => htslib::bam_aux_update_array(
1160+
self.inner_ptr_mut(),
1161+
ctag,
1162+
b'S',
1163+
inner.len() as u32,
1164+
inner.slice.as_ptr() as *mut ::libc::c_void,
1165+
),
1166+
},
1167+
Aux::ArrayI32(aux_array) => match aux_array {
1168+
AuxArray::TargetType(inner) => htslib::bam_aux_update_array(
1169+
self.inner_ptr_mut(),
1170+
ctag,
1171+
b'i',
1172+
inner.len() as u32,
1173+
inner.slice.as_ptr() as *mut ::libc::c_void,
1174+
),
1175+
AuxArray::RawLeBytes(inner) => htslib::bam_aux_update_array(
1176+
self.inner_ptr_mut(),
1177+
ctag,
1178+
b'i',
1179+
inner.len() as u32,
1180+
inner.slice.as_ptr() as *mut ::libc::c_void,
1181+
),
1182+
},
1183+
Aux::ArrayU32(aux_array) => match aux_array {
1184+
AuxArray::TargetType(inner) => htslib::bam_aux_update_array(
1185+
self.inner_ptr_mut(),
1186+
ctag,
1187+
b'I',
1188+
inner.len() as u32,
1189+
inner.slice.as_ptr() as *mut ::libc::c_void,
1190+
),
1191+
AuxArray::RawLeBytes(inner) => htslib::bam_aux_update_array(
1192+
self.inner_ptr_mut(),
1193+
ctag,
1194+
b'I',
1195+
inner.len() as u32,
1196+
inner.slice.as_ptr() as *mut ::libc::c_void,
1197+
),
1198+
},
1199+
Aux::ArrayFloat(aux_array) => match aux_array {
1200+
AuxArray::TargetType(inner) => htslib::bam_aux_update_array(
1201+
self.inner_ptr_mut(),
1202+
ctag,
1203+
b'f',
1204+
inner.len() as u32,
1205+
inner.slice.as_ptr() as *mut ::libc::c_void,
1206+
),
1207+
AuxArray::RawLeBytes(inner) => htslib::bam_aux_update_array(
1208+
self.inner_ptr_mut(),
1209+
ctag,
1210+
b'f',
1211+
inner.len() as u32,
1212+
inner.slice.as_ptr() as *mut ::libc::c_void,
1213+
),
1214+
},
1215+
}
1216+
};
1217+
1218+
if ret < 0 {
1219+
Err(Error::BamAux)
1220+
} else {
1221+
Ok(())
1222+
}
1223+
}
1224+
10711225
// Delete auxiliary tag.
10721226
pub fn remove_aux(&mut self, tag: &[u8]) -> Result<()> {
10731227
let c_str = ffi::CString::new(tag).map_err(|_| Error::BamAuxStringError)?;

src/errors.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ pub enum Error {
9191
BamAuxUnknownType,
9292
#[error("failed to add aux field, tag is already present")]
9393
BamAuxTagAlreadyPresent,
94+
#[error("updating the aux field for this datatype is not supported")]
95+
BamAuxTagUpdatingNotSupported,
9496

9597
// Errors for base modification fields
9698
#[error("no base modification tag found for record")]

0 commit comments

Comments
 (0)