module BinData::Skip::SkipUntilValidPlugin

def fast_search_for(obj)

def fast_search_for(obj)
  if obj.respond_to?(:asserted_binary_s)
    FastSearch.new(obj.asserted_binary_s, obj.rel_offset)
  else
    nil
  end
end

def fast_search_for_obj(obj)

perform a faster search for a valid object.
If a search object has an +asserted_value+ field then we
def fast_search_for_obj(obj)
  if BinData::Struct === obj
    obj.each_pair(true) do |_, field|
      fs = fast_search_for(field)
      return fs if fs
    end
  elsif BinData::BasePrimitive === obj
    return fast_search_for(obj)
  end
  nil
end

def next_search_index(io, fs)

def next_search_index(io, fs)
  buffer = binary_string("")
  # start searching at fast_search offset
  pos = fs.offset
  io.skip(fs.offset)
  loop do
    data = io.read(SEARCH_SIZE)
    raise EOFError, "no match" if data.nil?
    buffer << data
    index = buffer.index(fs.pattern)
    if index
      return pos + index - fs.offset
    end
    # advance buffer
    searched = buffer.slice!(0..-fs.pattern.size)
    pos += searched.size
  end
end

def read_and_return_value(io)

def read_and_return_value(io)
  prototype = get_parameter(:until_valid)
  validator = prototype.instantiate(nil, self)
  fs = fast_search_for_obj(validator)
  io.transform(ReadaheadIO.new) do |transformed_io, raw_io|
    pos = 0
    loop do
      seek_to_pos(pos, raw_io)
      validator.clear
      validator.do_read(transformed_io)
      break
    rescue ValidityError
      pos += 1
      if fs
        seek_to_pos(pos, raw_io)
        pos += next_search_index(raw_io, fs)
      end
    end
    seek_to_pos(pos, raw_io)
    @skip_length = pos
  end
end

def seek_to_pos(pos, io)

def seek_to_pos(pos, io)
  io.rollback
  io.skip(pos)
end

def skip_length

def skip_length
  @skip_length ||= 0
end