Skip to content
13 changes: 8 additions & 5 deletions .github/workflows/rake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,28 @@ jobs:
before-setup-ruby: |
set -e
mkdir -p /tmp/tb && cd /tmp/tb
curl -sL https://api.github.com/repos/lutaml/taurus/tarball/v0.12.0 | tar xz --strip-components=1
curl -sL https://api.github.com/repos/lutaml/taurus/tarball/main | tar xz --strip-components=1
cmake -B build -S . \
-DCMAKE_BUILD_TYPE=Release \
-DTAURUS_BUILD_SHARED=ON \
-DTAURUS_BUILD_STATIC=OFF \
-DCMAKE_WINDOWS_EXPORT_ALL_SYMBOLS=ON \
-DBUILD_TESTING=OFF \
-DTAURUS_BUILD_CLI=OFF \
-DTAURUS_BUILD_BENCHMARKS=OFF \
-DTAURUS_BUILD_MAN_PAGES=OFF \
-DTAURUS_ENABLE_UTF8PROC=OFF \
-DTAURUS_ENABLE_ICONV=OFF
cmake --build build -j 4
LIB=$(find build/src -type f -o -type l 2>/dev/null | grep -E 'libtaurus\.(dylib|so|dll)$' | head -1)
LIB=$(find build -type f -o -type l 2>/dev/null | grep -iE '(lib)?taurus\.(dylib|so|dll)$' | head -1)
if [ -z "$LIB" ]; then
echo "ERROR: libtaurus shared library not found after build"
find build/src -name 'libtaurus*'
find build -name '*taurus*' -type f
exit 1
fi
echo "TAURUS_LIB_PATH=$(pwd)/$LIB" >> "$GITHUB_ENV"
echo "Installed libtaurus at: $(pwd)/$LIB"
# Convert to native path for Ruby FFI (Git-bash /tmp/ → C:\... on Windows)
LIBPATH=$(cygpath -w "$(pwd)/$LIB" 2>/dev/null || echo "$(pwd)/$LIB")
echo "TAURUS_LIB_PATH=$LIBPATH" >> "$GITHUB_ENV"
echo "Installed libtaurus at: $LIBPATH"
secrets:
pat_token: ${{ secrets.LUTAML_CI_PAT_TOKEN }}
5 changes: 5 additions & 0 deletions lib/taurus/xml/ffi.rb
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ class SerializeOptions < ::FFI::Struct
[:taurus_node_ref], :int
attach_function :taurus_node_compare,
[:taurus_node_ref, :taurus_node_ref], :int
attach_function :taurus_node_traverse,
[:taurus_node_ref, :int, :pointer, :pointer], :int

attach_function :taurus_text_node_get_content,
[:taurus_node_ref], :string
Expand Down Expand Up @@ -410,6 +412,9 @@ class SerializeOptions < ::FFI::Struct

C14N_MODE_CANONICAL = 0
C14N_MODE_EXCLUSIVE = 1

TRAVERSE_PRE_ORDER = 0
TRAVERSE_POST_ORDER = 1
end
end
end
19 changes: 6 additions & 13 deletions lib/taurus/xml/node.rb
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,12 @@ def unlink
# callback (libtaurus #273); the per-node FFI cost is the floor.
def traverse
return enum_for(:traverse) unless block_given?
walk_post_order(@c_ptr, @document) { |n| yield n }
callback = ::FFI::Function.new(:int, [:pointer, :pointer], blocking: true) do |node_ptr, _|
yield Taurus::XML::Node.wrap(node_ptr, @document)
0
end
Taurus::XML::FFI.taurus_node_traverse(
@c_ptr, Taurus::XML::FFI::TRAVERSE_POST_ORDER, callback, nil)
end

def path
Expand Down Expand Up @@ -212,17 +217,5 @@ def as_element_or_self
# calls and wrapping nodes directly. Saves one Array + one NodeSet
# allocation per parent node.
#
# Still pays ~2 FFI calls per visited node (first_child + next_sibling).
# Beating Nokogiri on this benchmark needs C-side traverse with a
# callback (libtaurus #273); the per-node FFI cost is the floor.
def walk_post_order(ptr, doc, &block)
child_ptr = Taurus::XML::FFI.taurus_node_first_child(ptr)
until child_ptr.nil? || child_ptr.null?
walk_post_order(child_ptr, doc, &block)
child_ptr = Taurus::XML::FFI.taurus_node_next_sibling(child_ptr)
end
yield Taurus::XML::Node.wrap(ptr, doc)
end

include Taurus::XML::Searchable
end
Loading