Consolidate handling of "is this a literal" and "is this a value"
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / _Util.pm
index 518457c..1407ddc 100644 (file)
@@ -55,9 +55,15 @@ use DBIx::Class::Carp '^DBIx::Class|^DBICTest';
 
 use Carp 'croak';
 use Scalar::Util qw(weaken blessed reftype);
+use List::Util qw(first);
+use overload ();
 
 use base 'Exporter';
-our @EXPORT_OK = qw(sigwarn_silencer modver_gt_or_eq fail_on_internal_wantarray refcount hrefaddr is_exception);
+our @EXPORT_OK = qw(
+  sigwarn_silencer modver_gt_or_eq fail_on_internal_wantarray
+  refcount hrefaddr is_exception
+  is_plain_value is_literal_value
+);
 
 sub sigwarn_silencer ($) {
   my $pattern = shift;
@@ -153,6 +159,43 @@ sub modver_gt_or_eq ($$) {
   eval { $mod->VERSION($ver) } ? 1 : 0;
 }
 
+sub is_literal_value ($) {
+  (
+    ref $_[0] eq 'SCALAR'
+      or
+    ( ref $_[0] eq 'REF' and ref ${$_[0]} eq 'ARRAY' )
+  ) ? 1 : 0;
+}
+
+# FIXME XSify - this can be done so much more efficiently
+sub is_plain_value ($) {
+  no strict 'refs';
+  (
+    # plain scalar
+    (! length ref $_[0])
+      or
+    (
+      blessed $_[0]
+        and
+      # deliberately not using Devel::OverloadInfo - the checks we are
+      # intersted in are much more limited than the fullblown thing, and
+      # this is a relatively hot piece of code
+      (
+        # either has stringification which DBI prefers out of the box
+        #first { *{$_ . '::(""'}{CODE} } @{ mro::get_linear_isa( ref $_[0] ) }
+        overload::Method($_[0], '""')
+          or
+        # has nummification and fallback is *not* disabled
+        (
+          $_[1] = first { *{"${_}::(0+"}{CODE} } @{ mro::get_linear_isa( ref $_[0] ) }
+            and
+          ( ! defined ${"$_[1]::()"} or ${"$_[1]::()"} )
+        )
+      )
+    )
+  ) ? 1 : 0;
+}
+
 {
   my $list_ctx_ok_stack_marker;