diff --git a/modules/draw.mjs b/modules/draw.mjs index 0214c6298..89c35b10b 100644 --- a/modules/draw.mjs +++ b/modules/draw.mjs @@ -135,6 +135,7 @@ drawFuncs = { lst: [ { name: clTBranchFunc, icon: 'img_leaf_method', draw: () => import_tree().then(h => h.drawTree), opt: ';dump', noinspect: true }, { name: /^TBranch/, icon: 'img_branch', draw: () => import_tree().then(h => h.drawTree), dflt: 'expand', opt: ';dump', ctrl: 'dump', shift: kInspect, ignore_online: true, always_draw: true }, { name: /^TLeaf/, icon: 'img_leaf', noexpand: true, draw: () => import_tree().then(h => h.drawTree), opt: ';dump', ctrl: 'dump', ignore_online: true, always_draw: true }, + { name: 'ROOT::RNTuple', icon: 'img_tree', get_expand: () => import('./rntuple.mjs').then(h => h.tupleHierarchy) }, { name: clTList, icon: 'img_list', draw: () => import_h().then(h => h.drawList), get_expand: () => import_h().then(h => h.listHierarchy), dflt: 'expand' }, { name: clTHashList, sameas: clTList }, { name: clTObjArray, sameas: clTList }, diff --git a/modules/io.mjs b/modules/io.mjs index cfa66b2ac..ec6681e54 100644 --- a/modules/io.mjs +++ b/modules/io.mjs @@ -375,6 +375,11 @@ CustomStreamers = { func(buf, obj) { obj.$kind = 'TTree'; obj.$file = buf.fFile; } }, + 'ROOT::RNTuple': { + name: '$file', + func(buf, obj) { obj.$kind = 'ROOT::RNTuple'; obj.$file = buf.fFile; } + }, + RooRealVar(buf, obj) { const v = buf.last_read_version; buf.classStreamer(obj, 'RooAbsRealLValue'); diff --git a/modules/rntuple.mjs b/modules/rntuple.mjs new file mode 100644 index 000000000..b3da8292d --- /dev/null +++ b/modules/rntuple.mjs @@ -0,0 +1,86 @@ +import { R__unzip } from './io.mjs'; + + +class RNTupleDescriptorBuilder { + + deserializeHeader(header_blob) { + if (!header_blob) + return; + + this.xxhash3 = 1234; + this.featuresFlags = []; + this.name = 'rntuple'; + this.description = 'description'; + // this.deserializeSchemaDescription ... + } + + deserializeFooter(footer_blob) { + if (!footer_blob) + return; + this.xxhash3 = 1234; + } + +} + +/** @summary Very preliminary function to read header/footer from RNTuple + * @private */ +async function readHeaderFooter(tuple) { + if (!tuple.$file) + return false; + + // request header and footer buffers from the file + return tuple.$file.readBuffer([tuple.fSeekHeader, tuple.fNBytesHeader, tuple.fSeekFooter, tuple.fNBytesFooter]).then(blobs => { + if (blobs?.length !== 2) + return false; + + // unzip both buffers + return Promise.all([ + R__unzip(blobs[0], tuple.fLenHeader), + R__unzip(blobs[1], tuple.fLenFooter) + ]).then(unzip_blobs => { + const header_blob = unzip_blobs[0], + footer_blob = unzip_blobs[1]; + if (!header_blob || !footer_blob) + return false; + + // create builder description and decode it - dummy for the moment + + tuple.builder = new RNTupleDescriptorBuilder; + + tuple.builder.deserializeHeader(header_blob); + + tuple.builder.deserializeFooter(footer_blob); + + return true; + }); + }); +} + + +/** @summary Create hierarchy of ROOT::RNTuple object + * @desc Used by hierarchy painter to explore sub-elements + * @private */ +async function tupleHierarchy(tuple_node, tuple) { + tuple_node._childs = []; + // tuple_node._tuple = tuple; // set reference, will be used later by RNTuple::Draw + + return readHeaderFooter(tuple).then(res => { + if (!res) + return res; + + // just show which objects belongs to hierarchy + // one need to fill list of items from tuple.builder ... object + for (let k = 0; k < 3; ++k) { + tuple_node._childs.push({ + _name: `dummy${k}`, + _kind: 'ROOT::SomeBranchName', + _title: `Any title for dummy${k}`, + _obj: null + }); + } + + return true; + }); +} + +export { tupleHierarchy };